The WHERE construct masks the evaluation of expressions and assignments of values in array assignment statements. It does this according to the value of a logical array expression.
.--------------------------. .----------------------------. .---------------------. V | V | V | >>-WHERE_construct_statement----+----------------------+-+----+------------------------+-+----+-----------------+-+--END_WHERE_statement->< '-where_body_construct-' '-masked_ELSEWHERE_block-' '-ELSEWHERE_block-' |
>>-+-where_assignment_statement-+------------------------------>< | (1) | +-WHERE_statement------------+ | (2) | '-WHERE_construct------------'
Notes:
|
+---------------------------------Fortran 95---------------------------------+
>>-masked_ELSEWHERE_statement--+----------------------+-------->< '-where_body_construct-' |
+-----------------------------End of Fortran 95------------------------------+
>>-ELSEWHERE_statement--+----------------------+--------------->< '-where_body_construct-' |
Rules:
+---------------------------------Fortran 95---------------------------------+
+-----------------------------End of Fortran 95------------------------------+
To understand how to interpret masked array assignments, you need to understand the concepts of a control mask (mc) and a pending control mask (mp):
The value of mc is cumulative; the compiler determines the value using the
mask expressions of surrounding WHERE statements and the current mask
expression. Subsequent changes to the value of entities in a
mask_expr have no effect on the value of mc. The compiler evaluates the mask_expr only once for
each WHERE statement, WHERE construct statement, or
masked ELSEWHERE statement.
The following describes how the compiler interprets statements in a
WHERE, WHERE construct,
masked ELSEWHERE
, ELSEWHERE, or END WHERE statement. It describes the
effect on mc and mp and any further behavior of the statements, in order of
occurrence.
+---------------------------------Fortran 95---------------------------------+
+-----------------------------End of Fortran 95------------------------------+
+---------------------------------Fortran 95---------------------------------+
+-----------------------------End of Fortran 95------------------------------+
+---------------------------------Fortran 95---------------------------------+
The following occurs:
+-----------------------------End of Fortran 95------------------------------+
The following occurs:
After the compiler executes an END WHERE statement, mc and mp have the values they had prior to the execution of the corresponding WHERE construct statement.
The compiler assigns the values of the expr that correspond to the true values of mc to the corresponding elements of the variable.
If a non-elemental function reference occurs in the expr or variable of a where_assignment_statement or in a mask_expr, the compiler evaluates the function without any masked control; that is, it fully evaluates all of the function's argument expressions and then it fully evaluates the function. If the result is an array and the reference is not within the argument list of a non-elemental function, the compiler selects elements corresponding to true values in mc for use in evaluating the expr, variable, or mask_expr.
If an elemental intrinsic operation or function reference occurs in the expr or variable of a where_assignment_statement or in a mask_expr, and is not within the argument list of a non-elemental function reference, the compiler performs the operation or evaluates the function only for the elements corresponding to true values in mc.
If an array constructor appears in a where_assignment_statement or in a mask_expr, the compiler evaluates the array constructor without any masked control and then executes the where_assignment_statement or evaluates the mask_expr.
The execution of a function reference in the mask_expr of a WHERE statement is allowed to affect entities in the where_assignment_statement. Execution of an END WHERE has no effect.
The following example shows how control masks are updated. In this example, mask1, mask2, mask3, and mask4 are conformable logical arrays, mc is the control mask, and mp is the pending control mask. The compiler evaluates each mask expression once.
Sample code (with statement numbers shown in the comments):
WHERE (mask1) ! W1 * WHERE (mask2) ! W2 * ... ! W3 * ELSEWHERE (mask3) ! W4 * ... ! W5 * END WHERE ! W6 * ELSEWHERE (mask4) ! W7 * ... ! W8 * ELSEWHERE ! W9 ... ! W10 END WHERE ! W11
The compiler sets control and pending control masks as it executes each statement, as shown below:
+---------------------------------Fortran 95---------------------------------+
+-----------------------------End of Fortran 95------------------------------+
Statement W7
mc = .NOT. mask1
mp = (.NOT. mask1) .AND. (.NOT.
mask4)
mc = (.NOT. mask1) .AND. mask4
Statement W9
mc = (.NOT. mask1) .AND. (.NOT.
mask4)
Statement W11
mc = 0
mp = 0
The compiler uses the values of the control masks set by statements W2, W4, W7, and W9 when it executes the respective where_assignment_statements W3, W5, W8, and W10.
Migration Tip: Simplify logical evaluation of arrays FORTRAN 77 source: INTEGER A(10,10),B(10,10) Fortran 90 or Fortran 95 source: INTEGER A(10,10),B(10,10) |
REAL, DIMENSION(10) :: A,B,C,D WHERE (A>0.0) A = LOG(A) ! Only the positive elements of A ! are used in the LOG calculation. B = A ! The mask uses the original array A ! instead of the new array A. C = A / SUM(LOG(A)) ! A is evaluated by LOG, but ! the resulting array is an ! argument to a non-elemental ! function. All elements in A will ! be used in evaluating SUM. END WHERE WHERE (D>0.0) C = CSHIFT(A, 1) ! CSHIFT applies to all elements in array A, ! and the array element values of D determine ! which CSHIFT expression determines the ! corresponding element values of C. ELSEWHERE C = CSHIFT(A, 2) END WHERE END
+---------------------------------Fortran 95---------------------------------+
The following example shows an array constructor in a WHERE construct statement and in a masked ELSEWHERE mask_expr:
CALL SUB((/ 0, -4, 3, 6, 11, -2, 7, 14 /)) CONTAINS SUBROUTINE SUB(ARR) INTEGER ARR(:) INTEGER N N = SIZE(ARR) ! Data in array ARR at this point: ! ! A = | 0 -4 3 6 11 -2 7 14 | WHERE (ARR < 0) ARR = 0 ELSEWHERE (ARR < ARR((/(N-I, I=0, N-1)/))) ARR = 2 END WHERE ! Data in array ARR at this point: ! ! A = | 2 0 3 2 11 0 7 14 | END SUBROUTINE END
The following example shows a nested WHERE construct statement and masked ELSEWHERE statement with a where_construct_name:
INTEGER :: A(10, 10), B(10, 10) ... OUTERWHERE: WHERE (A < 10) INNERWHERE: WHERE (A < 0) B = 0 ELSEWHERE (A < 5) INNERWHERE B = 5 ELSEWHERE INNERWHERE B = 10 END WHERE INNERWHERE ELSEWHERE OUTERWHERE B = A END WHERE OUTERWHERE ...
+-----------------------------End of Fortran 95------------------------------+