Reputation: 199
I am not pro in Fortran95, but I am writing a code in it and I found that I want to mask the array values with -9999, if it does not have certain values.
Example: I have an array 'X' has values vary from 0 to 32768, and I want to mask the values of the array, if 'X' value is not equal to 0,1,2,16 or 18. I solved it with the following syntax:
if (X.eq.0.or.X.eq.1.or.X.eq.2.or.X.eq.16.or.X.eq.18) then
X=X
else
X=-9999
end if
But there any other way to mask array values in FORTRAN 95?
Upvotes: 2
Views: 243
Reputation: 2981
For these kinds of problems I find it convenient to define the .in.
operator, which returns whether or not a scalar is in an array, so:
1 .in. [0, 1, 2]
returns .true.
3 .in. [0, 1, 2]
returns .false.
[1, 3] .in. [0, 1, 2]
returns [.true., .false.]
This can be defined as
module in_module
implicit none
interface operator(.in.)
module procedure element_in_list
module procedure elements_in_list
end interface
contains
function element_in_list(lhs, rhs) result(output)
integer, intent(in) :: lhs
integer, intent(in) :: rhs(:)
logical :: output
output = any(lhs==rhs)
end function
function elements_in_list(lhs, rhs) result(output)
integer, intent(in) :: lhs(:)
integer, intent(in) :: rhs(:)
logical, allocatable :: output(:)
integer :: i
output = [(any(lhs(i)==rhs), i=1, size(lhs))]
end function
end module
With the .in.
operator defined, then if X
is an array you can write
where (.not. (X .in. [0, 1, 2, 16, 18])) X = -9999
which will convert e.g. X = [4, 5, 1, 3, 16]
to X = [-9999, -9999, 1, -9999, 16]
.
If you want to simplify things further (as the where
construct can be quite unwieldy), you can also define the function filter
which takes an array of logicals and returns the indices of the .true.
values, e.g. filter([.false., .true., .true.])
returns [2, 3]
.
This can be defined as:
function filter(input) result(output)
logical, intent(in) :: input(:)
integer, allocatable :: output(:)
integer :: i
output = pack([(i, i=1, size(input))], input)
end function
And then you can simply write
X(filter(.not. (X .in. [0, 1, 2, 16, 18]))) = -9999
Upvotes: 1
Reputation: 900
There is the where
statement that can mask the array, but given the logical you have shown its a bit ugly
where (.not.(X==0 || X==1 || X==2 || X==16 || X==18)) x = -9999
Upvotes: 2