jkp
jkp

Reputation: 165

collecting variables in a common place - fortran90

Thanks for the suggestions. I beg your pardon for not being clear enough. Let me describe it again to the best of my ability.

There are two models - A & B. Model A has a subroutine (which is not a part of module) compns.f which is called by a main program. Below, the compns.f code:

compns.f: (Model A)

 subroutine compns(deltim,fhout)      
 use var_repos, only: compns_var_dump

 open(unit=nlunit,file=gfs_namelist) ! reads a file for the variables deltim and fhout

 rewind (nlunit)

 read(nlunit,nam_mrf)

 print *, deltim,fhout               ! deltim = 360.0, fhout  = 6.0

 CALL compns_var_dump(deltim,fhout)  ! calls the subroutine and passes the variables

 end

Another module which contains the subroutine compns_var_dump (to collect the variables) is var_repos.f90:

MODULE var_repos

  IMPLICIT NONE

  PUBLIC :: compns_var_dump

  PUBLIC :: tstep_var_dump       !!! to dump variables from another place

  REAL, PUBLIC :: d_time    ! dummy variable

! declare the variables which will go public here:

  REAL,    PUBLIC :: deltim, fhout

CONTAINS

  SUBROUTINE compns_var_dump(deltim , fhout)

  REAL,    INTENT(inout) :: deltim , fhout

  d_time = deltim

  WRITE(*,*)'Inside var_repos: deltim = ',deltim,d_time

  END SUBROUTINE compns_var_dump

  SUBROUTINE tstep_var_dump

  ...

  END SUBROUTINE tstep_var_dump

END MODULE var_repos

Now, I need the variables from var_repos.f90 in model B. The module in model B which requires them is the following:

mo_time_control.f90: (Model B)

 MODULE time_control

 PUBLIC :: get_delta_time

CONTAINS

   REAL(dp) FUNCTION get_delta_time()

   USE var_repos,      ONLY: d_time

   IMPLICIT NONE

   REAL :: d_time

   REAL :: a_time            ! Testing

   get_delta_time = d_time

   a_time = d_time           ! Testing

   WRITE(*,*)'Inside function get_delta_time(): deltim= ',d_time,get_delta_time, a_time

   END FUNCTION get_delta_time

 END MODULE time_control

The outputs after running the models is as follows:

'Inside var_repos: deltim = ' 360.000 360.000

'Inside function get_delta_time(): deltim= ' 0.00000E+00 0.00000E+00 0.00000E+00

I hope that I am clear in this post. Is there a better way to do the above task? My philosophy was to collect the required variables from model A into one module through different subroutine calls, thus use this module as a repository and let model B use it for the variables it requires. Is this approach right?

Upvotes: 0

Views: 283

Answers (1)

M. S. B.
M. S. B.

Reputation: 29391

Try this example:

MODULE var_repos

  IMPLICIT NONE

  PUBLIC :: compns_var_dump

  REAL,    PUBLIC :: deltim, var2

CONTAINS

  SUBROUTINE compns_var_dump(deltim , fhout)

  REAL,    INTENT(in) :: deltim , fhout

  WRITE(*,*)'Inside var_repos: args = ', deltim, fhout
  var2 = fhout

  END SUBROUTINE compns_var_dump

END MODULE var_repos


program test

use var_repos

call compns_var_dump ( 2.0, 3.0 )

write (*, *) "in main:", deltim, var2

end program test

The output is :

 Inside var_repos: args =    2.00000000       3.00000000    
 in main:   0.00000000       3.00000000    

I believe that answer is that the argument deltim of the subroutine and the module variable of the same name are different variables. Creating a subroutine dummy argument of the same name as the module variable masks the module module rather than automatically copying the value to the module variable. So in main the module variable deltim didn't receive the value 2 and is undefined. With the compiler I used the random value that it had was zero; the value might be different on a different compiler. On the other hand, the variables fhout and var2 are different, with the dummy argument fhout being actively copied to var2. Therefore the value of module var2 is set and available to any routine (here the main program) that uses the module.

Edit: The solution is what I show for argument fhout and module variable var2. Call the dummy arguments ARG_varX and the module variables GBL_varX. Inside the subroutine use assignment statements to copy each ARG_varX to GBL_varX. Then any procedures that uses the module will have access to the variables GBL_varX, which will have the values they were sent into the subroutine. Does this solve your problem.

Edit 2: Here is a version of your new code. It seems to work. If there is a bug either I fixed it or it is outside of the code that you are showing:

MODULE var_repos

   IMPLICIT NONE

   PUBLIC :: compns_var_dump

   ! declare the variables which will go public here:

   REAL,    PUBLIC :: GBL_deltim, GBL_fhout

CONTAINS

   SUBROUTINE compns_var_dump(ARG_deltim, ARG_fhout)

      REAL,    INTENT(in) :: ARG_deltim , ARG_fhout

      GBL_deltim = ARG_deltim
      GBL_fhout = ARG_fhout

      WRITE(*,*)'Inside compns_var_dump:', ARG_deltim, GBL_deltim, GBL_fhout

   END SUBROUTINE compns_var_dump

END MODULE var_repos

! ------------------------------------------------------------

module my_b

contains

   subroutine compns ()
      use var_repos, only: compns_var_dump

      real :: deltim, fhout

      deltim = 360.0
      fhout  = 6.0


      write (*, *) "compns:", deltim, fhout

      CALL compns_var_dump(deltim,fhout)  ! calls the subroutine and passes the variables

   end subroutine compns

end module my_b

! ------------------------------------------------------------

MODULE time_control

   PUBLIC :: get_delta_time

CONTAINS

   FUNCTION get_delta_time()

      USE var_repos,      ONLY: GBL_deltim

      IMPLICIT NONE

      real :: get_delta_time

      REAL :: a_time            ! Testing

      get_delta_time = GBL_deltim

      a_time = GBL_deltim           ! Testing

      WRITE(*,*)'Inside function get_delta_time(): deltim= ', GBL_deltim, get_delta_time, a_time

   END FUNCTION get_delta_time

END MODULE time_control

! ------------------------------------------------------------

program main

   use var_repos, only: GBL_deltim, GBL_fhout
   use my_b, only: compns
   use time_control, only: get_delta_time

   real :: local_var

   call compns ()

   local_var = get_delta_time ()

   write (*, *) "main:", local_var, GBL_deltim, GBL_fhout

end program main

Upvotes: 1

Related Questions