views:

206

answers:

2

Hi,

I have two p*n arrays, y and ymiss. y contains real numbers and NA's. ymiss contains 1's and 0's, so that if y(i,j)==NA, ymiss(i,j)==0, and 1 otherwise. I also have 1*n array ydim which tells how many real numbers there is at y(1:p,n), so ydim has values 0 to p

In R programming language, I can do following:

if(ydim!=p && ydim!=0)  
  y(1:ydim(t), t) = y(ymiss(,t), t)

That code arranges all real numbers of y(,t) in like this

first there's for example y(,t) = (3,1,NA,6,2,NA) after the code it's y(,t) = (3,1,6,2,2,NA)

Now I will only need those first 1:ydim(t), so it doesn't matter what those rest are.

The question is, how can I do something like that in Fortran?

Thanks,

Jouni

+1  A: 

Hi

In Fortran you can't store na in an array of real numbers, you can only store real numbers. So you'll probably want to replace na's with some value not likely to be present in your data: huge() might be suitable. 2D arrays are no problem at all for Fortan. You might want to use a 2D array of logicals to replace ymiss rather than a 2D array of 1s and 0s.

There is no simple, intrinsic to achieve what you want, you'd need to write a function. However, a more Fortran way of doing things would be to use the array of logicals as a mask for the operations you want to carry out.

So, here's some fragmentary Fortran code, not tested:

! Declarations
real(8), dimension(m,n) :: y, ynew
logical, dimension(m,n) :: ymiss

! Executable
where (ymiss) ynew = func(y)  ! here func() is whatever your function is

Regards

Mark

High Performance Mark
+2  A: 

The "where statement" and the "merge" intrinsic function are powerful, operating on selected positions in arrays, but they don't move items to the front of an array. With old-fashioned code with explicit indexing (could be packaged into a function) e.g.:

k=1
do i=1, n
   if (ymiss (i) == 1) then
      y(k) = y(i)
      k = k + 1
   end if
end do

What you want could be done with array intrinsics using the "pack" intrinsic. Convert ymiss into a logical array: 0 --> .false., 1 --> .true.. Then use code like (tested without the second index):

y(1:ydim(t), t) = pack (y (:,t), ymiss (:,t))


Edit to add example code, showing use of Fortran intrinsics "where", "count" and "pack". "where" alone can't solve the problem, but "pack" can. I used "< -90" as NaN for this example. The step "y (ydim+1:LEN) = -99.0" isn't required by the OP, who doesn't need to use these elements.

program test1

integer, parameter :: LEN = 6
real, dimension (1:LEN) :: y = [3.0, 1.0, -99.0, 6.0, 2.0, -99.0 ]
real, dimension (1:LEN) :: y2
logical, dimension (1:LEN) :: ymiss
integer :: ydim

y2 = y
write (*, '(/ "The input array:" / 6(F6.1) )' )  y

where (y < -90.0)
   ymiss = .false.
elsewhere
   ymiss = .true.
end where

ydim = count (ymiss)

where (ymiss) y2 = y
write (*, '(/ "Masking with where does not rearrange:" / 6(F6.1) )' )  y2

y (1:ydim) = pack (y, ymiss)
y (ydim+1:LEN) = -99.0
write (*, '(/ "After using pack, and ""erasing"" the end:" / 6(F6.1) )' )  y


stop

end program test1

Output is:

The input array: 3.0 1.0 -99.0 6.0 2.0 -99.0

Masking with where does not rearrange: 3.0 1.0 -99.0 6.0 2.0 -99.0

After using pack, and "erasing" the end: 3.0 1.0 6.0 2.0 -99.0 -99.0

M. S. B.