Piyushkumar Patel
Piyushkumar Patel

Reputation: 199

Assign fill value to variable if it does not equal to certain values

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

Answers (2)

veryreverie
veryreverie

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

steve
steve

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

Related Questions