Class() pointer to a pointer in Fortran: odd behaviour - oop

I've had a good look around the previous posts and I don't think that this topic has been covered, hopefully somebody can help.
I'm writing a code in fortran 2003, and using ifort. I have the following types which I need to manipulate, which I have design to give the flexibility that I need:
module parameters
double precision, target :: cur_x(3)
type fundamental
double precision, pointer :: x => null()
end type fundamental
type, extends(fundamental) :: ion
class(fundamental), pointer :: core => null()
end type ion
SAVE
end module parameters
The idea being that I build up a kind of a linked list of particles by using the previous in the list as the core of the next. Note that in reality I will have a large number of extensions to 'fundamental', all of which can be the 'core' of other particles. I want the calculated quantities, x, to be in an array together in physical memory as I will be addressing subsets of them in fairly complicated ways, for which I want to use another set of pointers to cur_x
The initialisation of the code goes like this, where I have added some diagnostic lines:
use parameters
type(fundamental), target :: electron, proton
type(ion), target :: hydrogen
write(*,*)associated(electron%x),associated(proton%x), &
& associated(hydrogen%core),associated(hydrogen%core%x)
electron%x => cur_x(1)
hydrogen%core => proton
proton%x => cur_x(2)
hydrogen%x => cur_x(3)
cur_x = 1.0
write(*,*)electron%x,proton%x,hydrogen%x,hydrogen%core%x
which prints
F F F T
1.0 1.0 1.0 <garbage>
Where I expect proton%x and hydrogen%core%x to be the same address in memory (cur_x(2)). So I have two questions
I have initialised all my pointers to be null. Why does
associated(hydrogen%core%x) give true? If I try and nullify this
pointer at the top of the code I get inconsistent results; using
nullify(hydrogen%core%x)
results in a segmentation fault. Performing
hydrogen%core%x => null()
allows the code to run, but associated(hydrogen%core%x) remains true
I have made sure to associate the list of pointers from parent to child, as suggested in this summary of surprising errors in fortran. The fact that proton%x is working but hydrogen%core%x gives garbage is something I don't understand.
I can work around the problem but this would sacrifice the generality that I will need for more complex calculations. I would also quite like to understand what is going wrong here.
Thanks for your help!
Jim
EDIT: added in 'target' properties for various things; note that this were always in the code, i just forgot them in transferring to this post
EDIT: To clarify, my main issue with the above code is that the final write command gives an uninitialised output for hydrogen%core%x, even following the association commands after the first write. Even though I initialise core as null in my type definitions, there seems to be a problem with it; and if I try and nullify it at the top of the code the program crashes.

The basic problem is that hydrogen%core is not associated. The effect of associated(hydrogen%core%x) is therefore indeterministic. You just can not access/query a field (x) of a derived type pointer (hydrogen%core), if the pointer is not associated e.g. points to null() instead of an existing derived type instance in memory. Your compiler may generate a code, which does not immediately crash when you try it, but whatever is done after that is indeterministic, as you probably have already overwritten some data at random memory address.
Actually, I compiled a self-containing version of your code (see below) with various compilers and I got immediate segfaults at the first write statement. Using appropriate check options one of the binaries even reports the reason being in referencing the disassociated pointer hydrogen%core. If you comment out the problematic associated() query (as in the code below) all binaries run fine.
Also, please note, that the variables electron and proton must have the target attribute, otherwise the code should not even compile at all. If your compiler compiles the code without complaints, you should probably think about changing to an other one.
module parameters
implicit none
save
type :: fundamental
double precision, pointer :: x => null()
end type fundamental
type, extends(fundamental) :: ion
class(fundamental), pointer :: core => null()
end type ion
end module parameters
program test
use parameters
implicit none
type(fundamental), target :: electron, proton
type(ion) :: hydrogen
double precision, target :: cur_x(3)
! If you remove the comment in the next statement, the program will be indeterministic
! and probably crash.
write(*,*) associated(electron%x),associated(proton%x), &
& associated(hydrogen%core)!, associated(hydrogen%core%x)
electron%x => cur_x(1)
hydrogen%core => proton
proton%x => cur_x(2)
hydrogen%x => cur_x(3)
cur_x(:) = 1.0
write(*,*)electron%x,proton%x,hydrogen%x,hydrogen%core%x
end program test

If hydrogen%core is not associated, then it is a programming error to reference (or define) hydrogen%core%x as you do so in the first write statement. With that programming error present, anything goes from that point on.
You don't say what version of ifort you are using but there have been (and I think are extant, if I recall recent posts on the Intel forums) compiler bugs to do with polymorphic pointers.
That aside, for hydrogen%core to be pointed at the local proton variable, then proton must have the TARGET attribute. I would expect the compiler to diagnose this.

Related

Explicit interface in Fortran [duplicate]

I'm very new to Fortran, and for my research I need to get a monster of a model running, so I am learning as I am going along. So I'm sorry if I ask a "stupid" question.
I'm trying to compile (Mac OSX, from the command line) and I've already managed to solve a few things, but now I've come across something I am not sure how to fix. I think I get the idea behind the error, but again, not sure how to fix.
The model is huge, so I will only post the code sections that I think are relevant (though I could be wrong). I have a file with several subroutines, that starts with:
!==========================================================================================!
! This subroutine simply updates the budget variables. !
!------------------------------------------------------------------------------------------!
subroutine update_budget(csite,lsl,ipaa,ipaz)
use ed_state_vars, only : sitetype ! ! structure
implicit none
!----- Arguments -----------------------------------------------------------------------!
type(sitetype) , target :: csite
integer , intent(in) :: lsl
integer , intent(in) :: ipaa
integer , intent(in) :: ipaz
!----- Local variables. ----------------------------------------------------------------!
integer :: ipa
!----- External functions. -------------------------------------------------------------!
real , external :: compute_water_storage
real , external :: compute_energy_storage
real , external :: compute_co2_storage
!---------------------------------------------------------------------------------------!
do ipa=ipaa,ipaz
!------------------------------------------------------------------------------------!
! Computing the storage terms for CO2, energy, and water budgets. !
!------------------------------------------------------------------------------------!
csite%co2budget_initialstorage(ipa) = compute_co2_storage(csite,ipa)
csite%wbudget_initialstorage(ipa) = compute_water_storage(csite,lsl,ipa)
csite%ebudget_initialstorage(ipa) = compute_energy_storage(csite,lsl,ipa)
end do
return
end subroutine update_budget
!==========================================================================================!
!==========================================================================================!
I get error messages along the lines of
budget_utils.f90:20.54:
real , external :: compute_co2_storage
1
Error: Dummy argument 'csite' of procedure 'compute_co2_storage' at (1) has an attribute that requires an explicit interface for this procedure
(I get a bunch of them, but they are essentially all the same). Now, looking at ed_state_vars.f90 (which is "used" in the subroutine), I find
!============================================================================!
!============================================================================!
!---------------------------------------------------------------------------!
! Site type:
! The following are the patch level arrays that populate the current site.
!---------------------------------------------------------------------------!
type sitetype
integer :: npatches
! The global index of the first cohort in all patches
integer,pointer,dimension(:) :: paco_id
! The number of cohorts in each patch
integer,pointer,dimension(:) :: paco_n
! Global index of the first patch in this vector, across all patches
! on the grid
integer :: paglob_id
! The patches containing the cohort arrays
type(patchtype),pointer,dimension(:) :: patch
Etc etc - this goes one for another 500 lines or so.
So to get to the point, it seems like the original subroutine needs an explicit interface for its procedures in order to be able to use the (dummy) argument csite. Again, I am SO NEW to Fortran, but I am really trying to understand how it "thinks". I have been searching what it means to have an explicit interface, when (and how!) to use it etc. But I can't figure out how it applies in my case. Should I maybe use a different compiler (Intel?). Any hints?
Edit: So csite is declared a target in all procedures and from the declaration type(site type) contains a whole bunch of pointers, as specified in sitetype. But sitetype is being properly used from another module (ed_state_vars.f90) in all procedures. So I am still confused why it gives me the explicit interface error?
"explicit interface" means that the interface to the procedure (subroutine or function) is declared to the compiler. This allows the compiler to check consistency of arguments between calls to the procedure and the actual procedure. This can find a lot of programmer mistakes. You can do this writing out the interface with an interface statement but there is a far easier method: place the procedure into a module and use that module from any other entity that calls it -- from the main program or any procedure that is itself not in the module. But you don't use a procedure from another procedure in the same module -- they are automatically known to each other.
Placing a procedure into a module automatically makes its interface known to the compiler and available for cross-checking when it is useed. This is easier and less prone to mistakes than writing an interface. With an interface, you have to duplicate the procedure argument list. Then if you revise the procedure, you also have to revise the calls (of course!) but also the interface.
An explicit interface (interface statement or module) is required when you use "advanced" arguments. Otherwise the compiler doesn't know to generate the correct call
If you have a procedure that is useed, you shouldn't describe it with external. There are very few uses of external in modern Fortran -- so, remove the external attributes, put all of your procedures into a module, and use them.
I ran into the same problems you encountered whilst I was trying to install ED2 on my mac 10.9. I fixed it by including all the subroutines in that file in a module, that is:
module mymodule
contains
subroutine update_budget(csite,lsl,ipaa,ipaz)
other subroutines ecc.
end module mymodule
The same thing had to be done to some 10 to 15 other files in the package.
I have compiled all the files and produced the corresponding object files but now I am getting errors about undefined symbols. However I suspect these are independent of the modifications so if someone has the patience this might be a way to solve at least the interface problem.

Inheritance and pointers in Fortran

I have a type for linked lists in Fortran. It is pretty useless, outside of demonstrating linked lists. I hope to derive a type from it that I can put to some good use. My base class is link and my derived class is useful_link. link doesn't do much except create a new link and receives a pointer to that link. My intent is that useful_link will create a new useful_link and also pass some useful data to its new creation. (And, as you might guess, do a bunch of other stuff that I don't have time or space to discuss.) My first pass at writing the code is:
module links
type link
type(link), pointer :: child => null()
contains
procedure :: reproduce
end type link
contains
subroutine reproduce(this, child_ptr)
class(link) :: this
class(link), pointer :: child_ptr
allocate(this%child)
child_ptr => this%child
end subroutine reproduce
end module links
module useful_links
use links
type, extends(link) :: useful_link
real*8 :: dataval
contains
procedure :: reproduce_w_data
end type useful_link
contains
subroutine reproduce_w_data(this, child_ptr, dataval)
class(useful_link) :: this
class(useful_link), pointer :: child_ptr
call this%link%reproduce(child_ptr) ! <--- problem!
child_ptr%dataval = dataval
end subroutine reproduce_w_data
end module useful_links
This does not compile. gfortran tells me "Error: Actual argument to ‘child_ptr’ ... must have the same declared type", and the problem is with the call to reproduce within the subroutine reproduce_w_data. Also, if I re-write the code to remove the child_ptr arguments, and try to assign dataval to the new link with
this%child%dataval = dataval
then gfortran tell me "‘dataval’ ... is not a member of the ‘link’ structure". Well, this all makes sense, but surely there is some way to make this work. Anyone know what it is?
BTW, I have seen examples that use the select type construct, but that is horribly unwieldy and, if I understand it, I would have to add a new option to reproduce in the link type every time I added a new inheriting type, which seems to me to defeat one of the purposes of OOP. Am I right about that? I'm pretty new to OOP in Fortan.
Finally, could anyone recommend a good reference on this? There seems to be many people out there who know this stuff well, but I can't find a place where it is all put together in one place.

How to explicitely use inherited variables in Fortran?

I have a question regarding best practices of model/variable usage:
Let's assume I have a module containing a few variable/parameter definitions and some subroutines that use these variables.
I do not need to explicitly use these variables in the subroutines since they are inherited from the parent module - but would it be better practice to do so?
Example:
module test
implicit none
integer, parameter :: a = 1
real :: x
contains
subroutine idk(y,z)
real, intent(in) :: y
real, intent(out) :: z
if(a .eq. 1) then
z = x*y + 5.
else
z = x*y - 5.
end if
end subroutine idk
end module test
The above example should work just fine but would it be better to add
use test, only: a,x
to the declaration part of subroutine idk?
In my reasoning, there are two main points here:
1) Pro: Explicitly adding this line let's me easily see which variables are actually needed in the subroutine.
In many cases, the module contains quite a number of variables but only a few are needed in each subroutine. So for reasons of better comprehensibility, it would be beneficial to add this line.
BUT
2) Contra: In quite a few cases, one needs a lot of the variables/parameters declared above (sometimes numbering more than 100 parameters). Explicitly using these at the beginning of the subroutine just unnecessarily clutters the code, reducing the readability of the code.
Point 1 matters mostly if only a few variables need to be included, whereas point 2 is only important if many variables need to be included. But I think it would be silly to do one thing for few variables and another for many - once you have picked a convention, you should stick to it IMHO...
Is there a best practice regarding this?
Addition:
Alternatively, one could declare the subroutine as
subroutine idk(b,w,y,z)
and then call it as idk(a,x,y,z).
On the one hand, this would give me greater flexibility if I later decide that I want to use idk with other variables.
On the other hand, it also increases the risk of mistakes if I change something later (say, I realize I don't need parameter a as a condition but parameter c. In the first cases, I simply switch out a -> c in the subroutine. But in the last case, I need to change every call to idk(c,...). If there are a lot of these calls, this is prone to mistakes)
I would really appreciate your input! Thank you!
There is absolutely no reason to use the module currently being defined. It is illegal. It may happen to compile if the module was compiled before and the compiler can find the .mod file, but file, but other than that it is wrong.
You should expect error such as
ifort -c assoc.f90
assoc.f90(10): error #6928: The module-name on a USE statement in a program unit cannot be the name of any encompassing scoping unit. [TEST]
use test
------^
The module subroutine gets the variables from the host module through host association and the use statement is for use association. These are two different things and should not be mixed.
If you want to avoid global variables, pass them as arguments. This is a general advice. What is best depends on each case and the programmer and cannot be answered generally.

Fortran: Whole array operations in Fixed Form Source

I am getting "Segmentation Fault" error over and over again, while using my subroutines (I have put all of them in MODULEs) with a code written in Fixed Form Source (during fortran77 days).
The original make file (Linux platform) is a mess, it compiles only ".f" source, so I had to change the extensions of my files from ".f90" to ".f", and have left first 7 columns blank in my modules.
My modules extensively use whole array operations and operations on array-sections, and I declare the variables in F90 style, many of them are assumed-size arrays.
My question:- although the compiler compiles these modules (having whole-array/array-section operations) without any warning/error, however is this "segmentation fault" due to the usage of modules with whole-array/array-section operations (kept in .f files) in a legacy code?
For example I have written following code in "algebra.f" module:
function dyad_vv(v1,v2) !dyadic product of two vectors
real*8, dimension(:)::v1,v2
real*8, dimension(size(v1,1),size(v2,1))::dyad_vv
integer i,j
do i=1,size(v1,1)
do j=1,size(v2,1)
dyad_vv(i,j)=v1(i)*v2(j)
end do
end do
end function
!==================================
function dot_mv(m,v) !dot product of a matrix and a vector
real*8, dimension(:,:)::m
real*8, dimension(:)::v
real*8, dimension(size(m,1))::dot_mv
integer i,j
do i=1,size(m,1)
dot_mv(i)=0.0000D0
do j=1,size(v,1)
dot_mv(i)=dot_mv(i)+m(i,j)*v(j)
end do
end do
end function
!==================================
function dot_vm(v,m) !dot product of a vector and a matrix
real*8, dimension(:)::v
real*8, dimension(:,:)::m
real*8, dimension(size(m,2))::dot_vm
integer i,j
do i=1,size(m,2)
dot_vm(i)=0.0000D0
do j=1,size(v,1)
dot_vm(i)=dot_vm(i)+v(j)*m(j,i)
end do
end do
end function
To expand a little on my already over-long comment:
Segmentation faults in Fortran programs generally arise from either (a) attempting to access an array element outside the array bounds, or (b) mismatching procedure actual arguments and dummy arguments.
Fortunately, intelligent use of your compiler can help you spot both these situations. For (a) you need to switch on run-time array bounds checking, and for (b) you need to switch on compile-time subroutine interface checking. Your compiler manual will tell you what flags you need to set.
One of the advantages of modern Fortran, in particular of modules is that you get procedure interface checking for free as it were, the compiler takes care, at compile time, of checking that dummy and actual arguments match.
So I don't think your problem stems directly from writing modern Fortran in fixed-source form. But I do think that writing modern Fortran in fixed-source form to avoid re-writing your makefile and to avoid upgrading some FORTRAN77 is a sufficiently perverse activity that you will find it painful in the short run, and regret it in the long run as you continue to develop degraded code.
Face up to it, refactor now.

Are local variables in Fortran 77 static or stack dynamic?

For my programming languages class one hw problem asks:
Are local variables in FORTRAN static or stack dynamic? Are local variables that are INITIALIZED to a default value static or stack dynamic? Show me some code with an explanation to back up your answer. Hint: The easiest way to check this is to have your program test the history sensitivity of a subprogram. Look at what happens when you initialize the local variable to a value and when you don’t. You may need to call more than one subprogram to lock in your answer with confidence.
I wrote a few subroutines:
- create a variable
- print the variable
- initialize the variable to a value
- print the variable again
Each successive call to the subroutine prints out the same random value for the variable when it is uninitialized and then it prints out the initialized value.
What is this random value when the variable is uninitialized?
Does this mean Fortran uses the same memory location for each call to the subroutine or it dynamically creates space and initializes the variable randomly?
My second subroutine also creates a variable, but then calls the first subroutine. The result is the same except the random number printed of the uninitialized variable is different. I am very confused. Please help!
Thank you so much.
In Fortran 77 & 90/95/2003, if you want the value of a variable local to a subroutine preserved across subroutine calls, you should declare it the "save" attribute, e.g., (using Fortran 90 style):
integer, save :: counter
OR
integer :: counter
save :: counter
.
Or, if you want the "save" behavior to apply to all variables just include in the subroutine a simple
save
statement without any variables.
In Fortran 90, a variable initialization in a declaration,
integer :: counter = 0
automatically acquires the save attribute. I don't think that this was the case in Fortran 77.
This is one area in which experiments could be misleading -- they will tell you what a particular compiler does, but perhaps not what the Fortran 77 language standard is, nor what other compilers did. Many old Fortran 77 compilers didn't place local variables on the stack and implicitly all variables had the save attribute, without the programming having used that declaration. This, for example, was the case with the popular DEC Fortran compilers. It is common for legacy Fortran 77 programs that were used only with a particular compiler of this type to malfunction with a modern compiler because programmers forgot to use the save attribute on variables that needed it. Originally this didn't cause a problem because all variables effectively had the save attribute. Most modern compilers place local variables without save on the stack, and these programs frequently malfunction because some variables that need "save" "forget" their values across subroutine calls. This can be fixed by identifying the problem variables and adding save (work), adding a save statement to every subroutine (less work), or many compilers have an option (e.g., -fno-automatic in gfortran) to restore the old behavior (easy).
It seems a peculiar question -- you won't find out about "Fortran 77" but about a particular compiler. And why use Fortran 77 instead of Fortran 95/2003? Does the prof. think Fortran stopped in 1977?
To amplify on one point that #MSB made;
Fortran standards do not tell compiler-writers how to implement the standards, they are concerned with the behaviour of programs visible to the programmer. So the answer to the question is 'it all depends on the compiler'. And OP does not tell us which compiler(s) (s)he is using.
Furthermore, if you trawl back through the mists of time to examine all the FORTRAN77 compilers ever written, I am confident that you will find a wide variety of different implementations of the features you are interested in, many of them tied to quite esoteric hardware architectures.