fortranassociate

Fortran: namelist + associate does not work


I store parameters in a derived type and I want to load them from a file through a namelist at run time. This is a sketch of the code:

module options_definitions
implicit none
type :: opts

integer :: option1
integer :: option2

contains
procedure :: load      => load_options

end type opts

contains

subroutine load_options(this,path_to_profiles_folder,profile_name)

class(opts),      intent(inout) :: this
character(len=*), intent(in)    :: path_to_profiles_folder
character(len=*), intent(in)    :: profile_name 
integer                         :: err, ios
logical                         :: file_exists
character(len=255)              :: err_message
character(len=255)              :: path_to_profile_folder

ASSOCIATE( option1    => this%option1, &
           option2    => this%option2)

namelist /options_nml/ option1, option2

! the following is INESSENTIAL added for completeness
!-----------------------------------------------------
path_to_profile_folder=trim(path_to_profiles_folder)//trim(profile_name)

! load options from the configuration file (namelist set above)
INQUIRE(FILE=trim(path_to_profile_folder)//'/'//trim(opt_file_name), EXIST=file_exists)   ! 'file_exists' will be TRUE if the file exists and FALSE otherwise

if (file_exists) then
   call my_open(111,trim(path_to_profile_folder)//'/'//trim(opt_file_name),&
      'Options module could not open the options configuration file')
   read(111,NML=options_nml,iostat=ios,iomsg=err_message)
   call check_read_success_and_close(111,trim(path_to_profile_folder)//'/'//trim(opt_file_name),ios,err_message,&
      'Options module could not read from the options configuration file')
else
   print*,'Warning: The required configuration file containing options &
      (options.nml) does not exist. The inbuilt options will be &
      used instead.'
endif
!---------------------------------------

end associate

end subroutine load_options

The compiler complains that option1, option2, ... have not been declared ( (iFort) error #6404: This name does not have a type, and must have an explicit type. [OPTION1]).

From the description of the namelist construct (https://software.intel.com/sites/products/documentation/doclib/stdxe/2013/composerxe/compiler/fortran-mac/GUID-EAC90ABA-859A-4745-B9FC-B8D66B5B6FF0.htm) I read that

each variable in var-list must be accessed by USE or host association

which I would say is the case here as this is a dummy argument with intent(inout). Isn't this the use association?

What is wrong? Is there a workaround such that I don't have to declare the same stuff many times in different places?

(e.g. declaring option1 as module private and copying it in this at the end of the load_options routine rather than using the associate construct would work but I would prefer something less prone to omissions when adding options later)

Thanks in advance for any comments.

PS: Just before posting I found this question. The code looks like it could be doing what I want but without seeing the definition of the unit type I cannot understand what it does.

EDIT1: Follow up on Vladimir's comments Now I quite understand what is going on. In the question I linked the author uses a pointer to this not to individual fields and this would be my preferred option if I could make it work. When I tried it the compiler was fine with the namelist declaration but refused to read from the input file saying

error #5498: Allocatable or pointer derived-type fields require a user-defined I/O procedure. read(111,NML=options_nml,iostat=ios,iomsg=err_message)

Any suggestions what such an I/O procedure could look like? I am confused, if it is possible to add a derived-type (or a pointer to it) in a namelist declaration then I would assume that the variables in the input file should be referred to as this%option1 and that would be it. I have found another discussion here where Steve Lionel from Intel supports this view saying

The Fortran standard allows only "variable-name" in the namelist object list. You can, however, put T in the namelist and reference T%I in namelist input (and it is shown on output).

But the compiler complains without even seeing the file.

EDIT2: What I changed in the code above (that lead to the compiler error in first edit) was this:

class(opts), intent(inout), target :: THIS
TYPE(opts), POINTER :: THIS_NML

namelist /options_nml/ THIS_NML
THIS_NML => THIS

The associate construct deleted, the original namelist declaration deleted. The error occurred in the read statement in the if (file_exists) block. So what I did was to use a pointer to a structure in the namelist declaration. That was all.


Solution

  • For ifort you can actually use the solution from my answer you linked. The exact definition of unit is not important there.

    select type(t => this)
      type is (opts)
    
        associate( option1    => t%option1, &
                   option2    => t%option2)
    
          namelist /options_nml/ option1, option2
    
          read...
        end associate
    end select
    

    This is because this is polymorphic in your example.

    I investigated, whether this usage is standard conforming, and it is not. Ifort clearly warns, when asked to follow the standard

    ifort -stand f08  namelist.f90
    namelist.f90(8): warning #7775: Placement of NAMELIST statement is non-standard.
    

    There are many other workarounds you can do. You can create local pointers and read them in the namelist read, that is exactly what the answer linked by you does. That would compile also with gfortran. I would go this way.

    integer, pointer :: option1, option2
    
    namelist /options_nml/ option1, option2
    
    option1 => this%option1
    option2 => this%option2
    
    read...
    

    Or use normal local variables and copy the values to this.