Dear Prof Lewis,
NAG Team took a look at this problem (they have very good support), and they wrote to me. According to them:
The CAMB Reionization module is essentially doing
Code: Select all
Module m
Integer, Pointer, Private :: m_p
Contains
Subroutine s1(p)
Integer, Target :: p
m_p => p
Call s2(p)
End Subroutine
Subroutine s2(i)
Integer :: i
Call s3(i)
Print *, m_p
End Subroutine
Subroutine s3(p)
Integer, Target :: p
m_p => p
End Subroutine
End Module
Program foo
Use m
Integer :: i
Call s1(i)
End Program
The fact that i in s2 does not have the Target attribute is what changes
the semantics of the code and makes m_p dangle after returning from s3.
The Fortran standard states
"If the dummy argument has the TARGET attribute and the effective
argument does not have the TARGET attribute or is an array section with
a vector subscript, any pointers associated with the dummy argument
become undefined when execution of the procedure completes."
I attach a patch to fix this. Note though that my code does not free the
cp%reion and cp%reionhist allocated in CAMBParams_Set.
I observe that the code still fails at runtime when checking for
undefined variables is active (-C=undefined) at the point that a deep
copy of a partly uninitialized derived type is attempted:
Runtime Error: camb.f90, line 125: Reference to undefined variable PARAMS
Program terminated by fatal error
camb.f90, line 125: Error occurred in CAMB:CAMB_GETRESULTS
inidriver.F90, line 321: Called by DRIVER
I suppose a solution to this, if some of the components of PARAMS being
set or not is conditional on the problem's state, might be to split the
data into smaller pieces (i.e. using smaller type definitions) to
reflect that. Or maybe to write a custom assignment routine to skip
components that are known to be uninitialized in certain contexts.
The code also fails when call checking is enabled (-C=calls)
Runtime Error: subroutines.f90, line 370: Invalid procedure reference -
Actual argument for dummy argument EV is derived-type instead of
REAL(real32)
Program terminated by fatal error
subroutines.f90, line 370: Error occurred in DVERK
recfast.f90, line 669: Called by RECOMBINATION:RECOMBINATION_INIT
modules.f90, line 2664: Called by THERMODATA:INITHERMO
cmbmain.f90, line 768: Called by CAMBMAIN:INITVARS
cmbmain.f90, line 157: Called by CAMBMAIN:CMBMAIN
camb.f90, line 137: Called by CAMB:CAMB_GETRESULTS
inidriver.F90, line 321: Called by DRIVER
I can see from the code that this is in some sense 'anticipated'.
Nevertheless, it is illegal Fortran. The suggestion in the code to use
Class (*) instead seems reasonable. Alternatively, what we do in such
cases in the NAG Library is just to 'cast' the data into an opaque c_ptr
type (using the facilities from the Fortran 2003 iso_c_binding module) -
a bit like a void * in C.
I can send you the patch if you want.
Best
Vinicius