Fortran: namelist + associate does not work - fortran

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.

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.

Related

iso_fortran_env kind values not compile-time constant [duplicate]

In a Fortran 2003 module I'm defining a type called t_savepoint and, later, I want to define an interface for a subroutine called fs_initializesavepoint, which takes an object of type t_savepoint as only argument.
Here is the code for the whole module:
module m_serialization
implicit none
type :: t_savepoint
integer :: savepoint_index
real :: savepoint_value
end type t_savepoint
interface
subroutine fs_initializesavepoint(savepoint)
type(t_savepoint) :: savepoint
end subroutine fs_initializesavepoint
end interface
end module m_serialization
The reason why I want such an interface is that later on I will make this fortran module interoperate with C.
If I try to compile it (gfortran-4.7.0), I get the following error message:
type(t_savepoint) :: savepoint
1
Error: The type of 'savepoint' at (1) has not been declared within the interface
The error disappears if I move the definition of the type inside the subroutine; but if then I want to use the same type within many subroutines, should I repeat the definition in all of them?
Thank you in advance.
EDIT: a solution would be to move the definition of the type onto another module and then to use it in every subroutine. However I don't like this solution too much, because the type t_savepoint and the subroutines are part of the same conceptual topic.
Rightly or wrongly in an interface block you don't have access to the environment by host association. To fix this you need to import the datatype exlicitly:
[luser#cromer stackoverflow]$ cat type.f90
module m_serialization
implicit none
type :: t_savepoint
integer :: savepoint_index
real :: savepoint_value
end type t_savepoint
interface
subroutine fs_initializesavepoint(savepoint)
Import :: t_savepoint
type(t_savepoint) :: savepoint
end subroutine fs_initializesavepoint
end interface
end module m_serialization
[luser#cromer stackoverflow]$ gfortran -c type.f90
This is f2003.
However I suspect the way you have put this suggests you are not going about coding this up the best way. Better is simply to put the routine itself in the module. Then you don't need bother with the interface at all:
module m_serialization
implicit none
type :: t_savepoint
integer :: savepoint_index
real :: savepoint_value
end type t_savepoint
Contains
Subroutine fs_initializesavepoint(savepoint)
type(t_savepoint) :: savepoint
Write( *, * ) savepoint%savepoint_index, savepoint%savepoint_value
End Subroutine fs_initializesavepoint
end module m_serialization
[luser#cromer stackoverflow]$ gfortran -c type.f90
Given that modules are really designed to deal with connected entities this is really the way to do it in Fortran. It also has the advantage of only requiring a f95 compiler, so is universally available (though admittedly import is commonly implemented)

error: 'x' argument pf 'dtime' intrinsic at <1> must be of kind 4

My understanding of programming is very limited so I hope I am making sense.
I made a change to a fixed variable in a program (the program is called NAFnoise; I was using the .exe but it came with the source code and I made the change there). The program is written in Fortran and is in multiple files. I am using gfortran to compile it and most of the files works without a problem. One file, however, is giving me trouble. And I didn't even make changes to it. It is giving error messages that is like this:
error: 'x' argument pf 'dtime' intrinsic at <1> must be of kind 4
The same message appears for etime. The only times those (I am guessing they are) functions and variables inside them are referenced as shown below:
IMPLICIT NONE
! Local variables.
INTEGER(4) :: klo,khi,i,n_in,nvar,nj,j1,j2,ivar,nok,nbad
REAL(DbKi) :: kk2, Isumwell, Isum, Itot,eps,h1,hmin
REAL(DbKi) :: ys1,ys2,poverall,phipot
REAL(DbKi) :: bigben(2),bigben2(2),dtime,etime
REAL(DbKi) :: phif(10)
COMPLEX(DbKi) :: value,dval1,dval2,dval11,dval12,dval22
COMPLEX(DbKi) :: btrans,btrans1,btrans2,btrans11,btrans12,btrans22
COMPLEX(DbKi) :: bbb,bbb1,bbb2
and
write(*,*) etime(bigben2),dtime(bigben)
and
write(*,*) etime(bigben2),dtime(bigben)
I am guessing the program was found when the author included it in the source folder, so I am not sure what went wrong. The variable I change should have nothing to do with this. Does it have something to do with the compiler? How can it be fixed?
DTIME is a non-standard GNU function described in the manual https://gcc.gnu.org/onlinedocs/gfortran/DTIME.html. It requires an argument to be of kind 4. That is the single precision under the default settingd for gfortran.
Probably, DbKi means double precision instead for you. Change
REAL(DbKi) :: bigben(2),bigben2(2),dtime,etime
to
REAL :: bigben(2),bigben2(2)
(or real(4)) if you use the GNU intrinsic extension.
If you actually want to call some your own external dtime, you must declare an interface block for it.
The same holds for etime from https://gcc.gnu.org/onlinedocs/gfortran/ETIME.html

What is this fortran parameter declaration doing and why is it doing it?

I have a parameter being declared in a fortran header file like this:
parameter (param=((0-565)))
param always seems to be valued at 565. Basis tutorials on parameters don't include information about what the ((0-565)) actually means in this context and my google-fu isn't up to this challenge.
The code
program main
implicit none
integer :: param
parameter (param=((0-565)))
! integer, parameter :: param = -565 ! suggest replacing two lines above with this
print*,"param =",param
end program main
sets param to -565, as confirmed by both g95 and gfortran. The comment line uses a suggested modern syntax, assuming param is of the integer data type.

Creating a simple subroutine in fortran

I am new to Fortran and I had made a program where everything did fit into one single file, which worked.
However when i tried to take out parts and put them into modules and subroutines I quickly ran into problems.
Even after removing everything and having only the bare minimum left, it still gives an error regarding the subroutine.
Currently the heavily reduced main program looks like this. It only uses the module and calls the subroutine.
program test
use mod1
call sub1(var)
end program test
and the module looks like:
Module mod1
implicit none
type A
real :: type1
end type A
contains
subroutine sub1(var)
type(A) :: var
var%type1 = 1+1
end subroutine sub1
However I seem to do something wrong here and unfortunately I can not figure out what. I get the error
||Error: Type mismatch in argument 'var' ; passed REAL(4) to TYPE(a)|
end module mod1
Can someone please explain which fundamental mistake I am making in order to prevent the most basic subroutine from working?
In your program you do not explicitly declare var. In days of yore Fortran supported implicit typing and, by default, variables whose name begin with a v will be of type real. Fortran retains this capability, though its use is now frowned upon.
I think you are thinking (as if I had a clue what you are thinking) that var in the program scope will somehow be automatically associated with, or the same as, var in the subroutine in the module. It won't be.
Do these things:
Insert implicit none on the line after use mod1 in your program.
Explicitly declare var within the program, eg type(a) :: var

Pass kind parameter to subprogram

Is it possible in modern versions of Fortran to pass a kind parameter to a subprogram and to use this to 'cast' variables to this kind? As an example, in the following code I am trying to convert an default integer to an 16-bit integer before printing it.
program mwe
! Could use iso_fortran_env definition of int16, but I am stuck with
! old versions of ifort and gfortran.
! use, intrinsic :: iso_fortran_env, only : int16
implicit none
! 16-bit (short) integer kind.
integer, parameter :: int16 = selected_int_kind(15)
call convert_print(123, int16)
contains
subroutine convert_print(i, ikind)
implicit none
integer, intent(in) :: i
integer, intent(in) :: ikind
print*, int(i, ikind)
end subroutine convert_print
end program mwe
With this example code the Intel Fortran compiler complains that
mwe.f(24): error #6238: An integer constant expression is required in this context. [IKIND]
...
mwe.f(24): error #6683: A kind type parameter must be a compile-time constant [IKIND]
and gfortran complains
'kind' argument of 'int' intrinsic at (1) must be a constant
Using print*, int(i, int16) in place of print*, int(i, ikind) would of course work fine in this case. However, if convert_print were defined in a a module which does not define int16 then this would be useless.
Is there a way of passing a kind parameter as a constant to subprograms?
I have the same problem. I find extremely inconvenient that it is not allowed to pass the kind datatype as an argument to a procedures. In my case, I am writing write a subroutine to just read a matrix from a file and get the object in the data type that I want to. I had to write four different subroutines: ReadMatrix_int8(…), ReadMatrix_int16(…), ReadMatrix_int32(…) and ReadMatrix_int64(…) which are nothing but the same code with one single line different:
integer(kind=xxxx), allocatable, intent(out) :: matrix(:,:)
It would make sense to write only one subroutine and pass xxxx as an argument. If I find any solution I will let you know. But I am afraid that there is no better solution than writing the four subroutines and then writing an interface to create a generic procedure like:
interface ReadMatrix
module procedure ReadMatrix_int8
module procedure ReadMatrix_int16
module procedure ReadMatrix_int32
module procedure ReadMatrix_int64
end interface
As far as I can work out, what I am trying to do is expressly forbidden by the Fortran 2003 standard (PDF, 4.5 MB):
5.1.2.10 PARAMETER attribute
A named constant shall not be referenced unless it has been defined previously in the same statement, defined in a prior statement, or made accessible by use or host association.
Therefore is seems that I need to define a function for each conversion I wish to do, for example:
subroutine print_byte(i)
implicit none
integer, intent(in) :: i
print*, int(i, int8)
end subroutine print_byte
subroutine print_short(i)
implicit none
integer, intent(in) :: i
print*, int(i, int16)
end subroutine print_short
subroutine print_long(i)
implicit none
integer, intent(in) :: i
print*, int(i, int32)
end subroutine print_long
Obviously all of the above will have to be overloaded to accept different kinds of the input argument. This seems like a lot of work to get around not being able to pass a constant, so if someone has a better solution I am keen to see it.
This Intel expert gives an explanation and an elegant solution. I couldn't explain it better. A full cite follows:
"One day while I was wandering the aisles of my local grocery store, a woman beckoned me over to a table and asked if I would like to "try some imported chocolate?" Neatly arrayed on the table were packages of Lindt, Toblerone, and... Ghiradelli? I asked the woman if California had seceded from the Union, as Ghiradelli, despite its Italian name, hails from San Francisco. I suppose that from the vantage point of New Hampshire, California might as well be another country, much as depicted in that famous Saul Steinberg 1976 cover for The New Yorker, "View of the World from 9th Avenue".
(I've been warned that my blogs don't have enough arbitrary links - this should hold 'em for a while.)
Similarly, in Fortran (I'll bet you were wondering when I'd get to that), something can be so near yet seem so far away. A short time ago, I was writing a new module for Intel Visual Fortran to provide declarations for the Win32 Process Status API. This would contain declarations of types and constants as well as interface blocks for the API routines, some of which take arguments of the new type. The natural inclination is to write something like this:
MODULE psapi
TYPE sometype
some component
END TYPE sometype
INTERFACE
FUNCTION newroutine (arg)
INTEGER :: newroutine
TYPE (sometype) :: arg
END FUNCTION newroutine
END INTERFACE
END MODULE psapi
If you did and compiled it, you'd get an error that type sometype is undefined in the declaration of arg. "What? It's not undeclared, I can see it right above in the same module!" Well, yes and no. Yes, it's declared in the module and could be used anywhere in the module, except.. Except in interface blocks!
The problem is that interface blocks are a "window into the external routine" - they essentially duplicate the declarations you would see in the actual external routine, assuming that routine were written in Fortran. As such, they do not "host associate" any symbols from the enclosing scoping unit (the module in this case.)
In Fortran 90 and Fortran 95, the typical solution for this was to create a separate module, say, "psapi_types", containing all of the types and constants to be used, You'd then add a USE statement inside each function, just as you would have to in the hypothetical external routine written in Fortran. (If it were written in Fortran, the Doctor would slap your wrist with a wet punchcard and tell you to make the routine a module procedure, and then you wouldn't need to worry about this nonsense.) So you would end up with something like this:
MODULE psapi
USE psapi_types ! This is for the benefit of users of module psapi
INTERFACE
FUNCTION newroutine (arg)
USE psapi_types
INTEGER :: newroutine
TYPE (sometype) :: arg
...
Those of you who use Intel Visual Fortran know that in fact there's a giant module IFWINTY for this purpose, containing all of the types and constants for the other Win32 APIs. It's messy and inelegant, but that's what you have to do. Until now...
Fortran 2003 attempts to restore some elegance to this sorry situation, but to preserve compatibility with older sources, it couldn't just declare that interface blocks participate in host association. Instead, a new statement was created, IMPORT. IMPORT is allowed to appear in interface blocks only and it tells the compiler to import names visible in the host scope.
IMPORT is placed following any USE statements but before any IMPLICIT statements in an interface body (the FUNCTION or SUBROUTINE declaration). IMPORT can have an optional import-name-list, much like USE. Without one, all entities accessible in the host become visible inside the interface body. With a list, only the named entities are visible.
With IMPORT, my PSAPI module can look like the first example with the following change:
...
FUNCTION newroutine (arg)
IMPORT
INTEGER :: newroutine
TYPE(sometype) :: arg
...
I could, if I wanted to, use:
IMPORT :: sometype
to say that I wanted only that one name imported. Nice and neat and all in one module!
"But why are you telling me this?", you might ask, "That's a Fortran 2003 feature and Intel Fortran doesn't yet do all of Fortran 2003." True enough, but we keep adding more and more F2003 features to the compiler and IMPORT made it in back in August! So if you are keeping reasonbly current, you can now IMPORT to your heart's content and do away with the mess of a separate module for your types and constants.
If you want to know what other F2003 goodies are available to you, just check the Release Notes for each update. A full list of supported F2003 features is in each issue. Collect 'em all!"