Geraldine
Geraldine

Reputation: 821

Fortran: reading input

I am trying to run a really large FORTRAN model, so I can't give all the code that's involved but I hope I can give enough information for this to make sense. The code compiled fine (using Intel 2016.0.109 compiler, OpenMPI 1.10.2 and HDF5 1.8.17).

When I try to run it though, it tells me that two of my inputs (called NZG and NZS) are set to -999, hence it fails.

> >>>>  opspec_grid  error! in your namelist!
>     ---> Reason:      Too few soil layers.  Set it to at least 2. Your nzg is currently set to -999...
>     ---> Reason:      Too few maximum # of snow layers. Set it to at least 1.  Your nzs is currently set to -999.

However, in the input file, they are really specified as

   NL%NZG  = 9
   NL%NZS  = 1

I went through all the modules that somehow have something to do with these variables and cannot find anywhere where this should go off the rails. So I am starting to think now that maybe there is something wrong with the way the values are read in. The input file is a text file. The variables are specified as integers in the module that reads them in, FYI. Should I check for special characters or something? I know Fortran can be picky with inputs...

EDIT: Below the code sequence tracing back the error

1) The main module opens the namelist

write (unit=*,fmt='(a)') 'Reading namelist information'
call read_nl(trim(name_name))

read_nl is

subroutine read_nl(namelist_name)
   use ename_coms, only : nl              & ! intent(inout)
                        , init_ename_vars ! ! subroutine

   implicit none
   !----- Arguments. ----------------------------------------------------------------------!
   character(len=*), intent(in) :: namelist_name
   !----- Local variables. ----------------------------------------------------------------!
   logical                      :: fexists
   !----- Name lists. ---------------------------------------------------------------------!
   namelist /ED_NL/ nl
   !---------------------------------------------------------------------------------------!

   !----- Open the namelist file. ---------------------------------------------------------!
   inquire (file=trim(namelist_name),exist=fexists)
   if (.not. fexists) then
      call fatal_error('The namelist file '//trim(namelist_name)//' is missing.'           &
                      ,'read_nl','ed_load_namelist.f90')
   end if

   !----- Initialise the name list with absurd, undefined values. -------------------------!
   call init_ename_vars(nl) 

   !----- Read grid point and options information from the namelist. ----------------------!
   open (unit=10, status='OLD', file=namelist_name)
   read (unit=10, nml=ED_NL)
   close(unit=10)

   return
end subroutine read_nl

2) Then there are specifics about how (what variables) to read from the namelist (the input)

write (unit=*,fmt='(a)') 'Copying namelist'
call copy_nl('ALL_CASES')  

if (runtype == 'HISTORY') then
  call copy_nl('HISTORY')
else
  call copy_nl('NOT_HISTORY')
end if

My simulation is 'NOT_HISTORY': copy_nl('ALL_CASES') is specified so it reads a number of the namelist variables, including the variable 'runtype' - which is then used in that if-else statement.

3) Then copy_nl('NOT_HISTORY') is the following, this is where nzg and nzs are defined.

subroutine copy_nl(copy_type)
use grid_coms            , only : time                      & ! intent(out)
                                   , centlon                   & ! intent(out)
                                   , centlat                   & ! intent(out)
                                   , deltax                    & ! intent(out)
                                   , deltay                    & ! intent(out)
                                   , nnxp                      & ! intent(out)
                                   , nnyp                      & ! intent(out)
                                   , nstratx                   & ! intent(out)
                                   , nstraty                   & ! intent(out)
                                   , polelat                   & ! intent(out)
                                   , polelon                   & ! intent(out)
                                   , ngrids                    & ! intent(out)
                                   , timmax                    & ! intent(out)
                                   , time                      & ! intent(out)
                                   , nzg                       & ! intent(out)
                                   , nzs                       ! ! intent(out)
implicit none
   !----- Arguments. ----------------------------------------------------------------------!
   character(len=*), intent(in) :: copy_type
   !----- Internal variables. -------------------------------------------------------------!
   integer                      :: ifm
   !---------------------------------------------------------------------------------------!

   !---------------------------------------------------------------------------------------!
   !     Here we decide which variables we should copy based on the input variable.        !
   !---------------------------------------------------------------------------------------!
select case (trim(copy_type))
case ('NOT_HISTORY')

  itimea        = nl%itimea
  idatea        = nl%idatea
  imontha       = nl%imontha
  iyeara        = nl%iyeara

  nzg           = nl%nzg
  nzs           = nl%nzs

  slz(1:nzgmax) = nl%slz(1:nzgmax)

  current_time%year  = iyeara
  current_time%month = imontha
  current_time%date  = idatea
  current_time%time  = real(int(real(itimea) * 0.01)) * hr_sec                         &
                     + (real(itimea) * 0.01 - real(int(real(itimea)*0.01)))            &
                     * 100.0 * min_sec
  time               = 0.0d0

NOTE that I have not put all the modules and variables in use, otherwise this post would become insanely long. FYI the module grid_coms specifies the type the variable is. See below the relevant part (the whole module is a list of variables, nothing else)

module grid_coms
  integer :: nzg                            ! Number of soil levels
  integer :: nzs                            ! Number of snow/surface water levels
end module grid_coms

4) Back to the main module, this then calls ed_opspec_grid to check that the variables make sense, and this is where things go wrong. Again, with use the variables are initialized at the start, I'm leaving that out here.

subroutine ed_opspec_grid
!---------------------------------------------------------------------------------------!
   !      Check whether soil layers are reasonable, i.e, enough layers, sorted from the !
   ! deepest to the shallowest.                                                            !
   !---------------------------------------------------------------------------------------!
   if (nzg < 2) then
      write (reason,'(a,1x,i4,a)')                                                         &
            'Too few soil layers.  Set it to at least 2. Your nzg is currently set to'     &
           ,nzg,'...'
      call opspec_fatal(reason,'opspec_grid')  
      ifaterr=ifaterr+1        
   elseif (nzg > nzgmax) then 
      write (reason,'(2(a,1x,i5,a))')                                                      &
            'The number of soil layers cannot be greater than ',nzgmax,'.'                 &
           ,' Your nzg is currently set to',nzg,'.'
      call opspec_fatal(reason,'opspec_grid') 
      ifaterr=ifaterr+1 
   end if
   do k=1,nzg
      if (slz(k) > -.001) then
         write (reason,'(a,1x,i4,1x,a,1x,es14.7,a)')                                       &
               'Your soil level #',k,'is not enough below ground. It is currently set to'  &
               ,slz(k),', make it deeper than -0.001...'
         call opspec_fatal(reason,'opspec_grid')  
         ifaterr=ifaterr+1        
      end if
   end do

   do k=1,nzg-1
      if (slz(k)-slz(k+1) > .001) then
         write (reason,'(2(a,1x,i4,1x),a,2x,a,1x,es14.7,1x,a,1x,es14.7,a)')                &
               'Soil layers #',k,'and',k+1,'are not enough apart (i.e. > 0.001).'          &
              ,'They are currently set as ',slz(k),'and',slz(k+1),'...'
         call opspec_fatal(reason,'opspec_grid')  
         ifaterr=ifaterr+1        
      end if
   end do
end subroutine ed_opspec_grid

NOTE that this is not the first check in this subroutine. Other variables are checked before this part (I left those out), but this is the first error message. Which makes me think that maybe part of the input is read okay and some is not.

Finally, let me stress again that this is a very large project, I really cannot show all the code, which is why I framed the question very simply: are there any (text) input requirements for Fortran that I might have missed (special characters, returns, maybe different for different systems?). Plus, this code is used by a lot of researchers, on different platforms, so I doubt it very much there is something wrong with the code itself... (but let me know if I'm wrong).

Upvotes: 1

Views: 653

Answers (1)

chw21
chw21

Reputation: 8140

You are not giving us enough data to pinpoint the issue, so I'll just tell you two of the issues that I have come across using namelists:

  1. If you read several (even different) namelists from the same file, the order counts: If in the file namelist a preceeds namelist b, but the code reads b first, then it won't find a unless you rewind the file.

  2. If the namelist in the data file does not include one or more values, these values will simply stay the same. It is quite likely that in the code these variables are set to -999 specifically so that their absence would be noted. So double-check that the data file is correct. Look for stray / characters that might end the namelist prematurely

All in all, in order to correctly assess what's happening, we'd need at least 3 things:

  1. The declaration block, including all the variables that form part of this namelist, and the namelist /.../ ...,...,... specification

  2. The part of the namelist file that declares this specific namelist, and

  3. Whether any other namelists are also in the same file and whether they're before or after this namelist (both in the file, and in the code)

Upvotes: 3

Related Questions