- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have been updating some fortran modeling software for streamflow simulation. Until recently I had primarily used gfortran for compiling the code. Having obtained a license for the Intel compilers on Macos I have started testing my code with ifort.
I have run into a problem with using pointers to dynamically allocated arrays. We have an object which handles the output of summary information from other objects' arrays. For efficiency all the other objects use the summary object to set pointers to the required dynamic arrays within those objects. This happens during the initialization/constructor phase of the program. With gfortran this has worked quite well but with ifort I have been getting segmentation faults. What appears to be happening is the address for a dynamically allocated array is different after returning from an object's constructor compared to what is after allocation within the constructor. Because the summary object's pointer is set during the constructor phase for each object (after an array has been allocated) this is causing all manner of mischief. After a lot of digging I have created what is hopefully a simple, reproducible test case.
I'm not sure if I'm just missing something incorrect in my approach or if this is some bug. When I run the test with gfortran the address for an array stays constant during program execution, however, with ifort the address for an array changes after returning from the constructor. I would appreciate any help/insight you could provide.
-parker
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Parker
just a quick thing. Have you tried to remove the call within the constructor to outside of the contructer.
So call the constructor and use its result to make the other call were you set the pointer
I suspect there could be an issue, since I faced similar problem before and that workaround worked for me.
If that is the problem that it could be a bug?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am reasonably certain that your constructor is building and returning a new "anonymous" ModC object. Then, a deep-copy of that object is being done on line 103:
module_c = ModC()
During this assignment, the 'module_c%first_arr' component is (re)allocated to match the size of the anonymous return value ModC%first_arr - then all of the data is copied from the anonymous result %first_arr into module_c%first_arr. I believe the pointer component is just being copied (hence your problem). So, after this assignment, module_c%first_arr is a newly allocated array that contains the same data as the object returned from the ModC() constructor - so it has a different address. Since the pointer component is (probably) copied, it is still pointing to the %first_arr component of the ModC object being returned by the constructor.
This is standard Fortran behavior to my knowledge - perhaps gfortran is just being "smart" by recognizing that the return value from the ModC() constructor is not otherwise used so it is just "moving" all of the components from the returned object into the module_c instance.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
nathan, parker wrote:.. I'm not sure if I'm just missing something incorrect in my approach or if this is some bug ..
You are employing intrinsic assignment with your derived type and in your particular situation, the behavior is effectively processor-dependent. You need to either refine your derived type design to work as you want given the rules in the standard with intrinsic assignment. Or you need to implement "defined assignment" to gain control over deep/shallow copy. Per the standard rules for intrinsic assignment, you can kinda view the component with the ALLOCATABLE attribute as getting a "deep copy" whereas that with POINTER attribute with a "shallow" one, note though the language in the standard is different. It just so happens the gfortran copy of the ALLOCATABLE component is an "efficient" one, a move! But you can't quite rely on that as portable behavior. You can try the somewhat shorter code below to compare and contrast the behavior with the 2 compilers:
module m type :: t integer, allocatable :: i integer, pointer :: ptr_i => null() character(len=10) :: id = "" end type interface t module procedure construct_t end interface contains function construct_t() result( new_t ) type(t), target :: new_t new_t%id = "new_t" new_t%i = 42 new_t%ptr_i => new_t%i call print_addr( new_t ) end function subroutine print_addr( this ) type(t), intent(in) :: this print *, "object id:", trim(this%id) print *, "loc(this%i) = ", loc(this%i) print *, "loc(this%ptr_i) = ", loc(this%ptr_i) end subroutine end module use m type(t) :: foo foo = t() foo%id = "foo" call print_addr( foo ) end
Upon execution with Intel Fortran,
object id:new_t loc(this%i) = 2418441855344 loc(this%ptr_i) = 2418441855344 object id:foo loc(this%i) = 2418441855200 loc(this%ptr_i) = 2418441855344
By the way, if I'm not mistaken, in your set_ptr procedure, the pointer association will be undefined once the procedure returns per the Fortran standard i.e., unless the actual argument has the TARGET (or POINTER) attribute.
Separately, you may want to reconsider your derived type design: if you can provide a more descriptive example of how exactly you plan to work with your "class" data, readers can perhaps offer other suggestions.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@FortranFan
I tried taking the call routine within the constructor and moved it out, you then obtain the expected results.
I still don’t understand it though. I had similar problem with constructors within constructors. At some point in execution the address simply just changed
is it generelly wise to have any calls whatsoever within a Fortran function?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Calls within a function are generally fine, as long as there are no side-effects on other things referenced in the expression that calls the function.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for the quick replies from everyone. My actual implementation is slightly more complicated than the example I provided. I wrote the example to get at the meat of the problem I am experiencing without going into more detail. Below is a fairly brief explanation of how I am using this in my code.
The model code has multiple objects/classes for the different physics required for a simulation. Each object has a mix of allocatable scalars and arrays that are used during computation; arrays only contain a single timestep of values over the model domain. There is a configuration file which contains (among other things) a list of variables are output to a netCDF summary file. These output variables can come from any of the requested physics objects. All summary -related operations are handled by a summary object. The summary object maintains an array of pointers to the output variables.
During the constructor phase the summary object is initialized first and then is passed to each physics object so they can set pointers to any of the scalars/arrays that are selected for output. When the model runs, the summary object writes the values to a file at the end of each timestep by using those pointers back to the original data.
I've attached another somewhat simple example that hopefully will give you an idea of what I'm doing. If the address of a given array changes after the constructor (at least with ifort) then what is the best way to handle this type of situation? I've been experimenting with defined assignment but so far I haven't seen any change in behavior. It's entirely possible that I'm just not understanding how to do this correctly. Granted there is room for interpretation in the standard on this, but the current approach by gfortran seems more intuitive, at least to me.
Let me know if you need more information or something I've said just doesn't make sense.
-parker
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
norton, parker wrote:.. Let me know if you need more information or something I've said just doesn't make sense. ..
If the main program you show in your latest file is your most likely use case of your derived types, your easiest option might be to follow the simple-minded approach which you will know of i.e., to transform your "constructor" function into type-bound subroutine "setter"/"initialization" procedures. And give your 'class' instance the TARGET attribute; toward this, you may want to investigate any performance impact in terms of missed optimization and check with Intel Sppport toward this as well. To illustrate this with the simpler example, so you can follow the KISS principle as follows:
module m type :: t integer, allocatable :: i integer, pointer :: ptr_i => null() character(len=10) :: id = "" contains private procedure, pass(this) :: init_t generic, public :: init => init_t end type contains subroutine init_t( this, i, id ) class(t), intent(inout), target :: this integer, intent(in) :: i character(len=*), intent(in) :: id this%id = id this%i = i this%ptr_i => this%i end subroutine subroutine print_addr( this ) type(t), intent(in) :: this print *, "object id: ", trim(this%id) print *, "loc(this%i) = ", loc(this%i) print *, "loc(this%ptr_i) = ", loc(this%ptr_i) end subroutine end module use m type(t), target :: foo call foo%init( i=42, id="foo" ) call print_addr( foo ) end
Upon execution with gfortran, you should find like htis:
object id: foo loc(this%i) = 18882432 loc(this%ptr_i) = 18882432
And with Intel Fortran,
object id: foo loc(this%i) = 2181581445808 loc(this%ptr_i) = 2181581445808
Given what the Fortran standard includes in terms of structure construction, which is rather limiting and nothing like NEW keyword in several widely-used OO languages, and how your "construction" instruction such as 'module_c = ModC()' translates effectively into a hodge-podge of a 'copy' operation, the use of a constructor can be more trouble than be beneficial.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
AT90 wrote:@FortranFan
I tried taking the call routine within the constructor and moved it out, you then obtain the expected results.
I still don’t understand it though. I had similar problem with constructors within constructors. At some point in execution the address simply just changed
is it generelly wise to have any calls whatsoever within a Fortran function?
See Quote #8.
With functions especially, you can try to follow a rule which is to apply the PURE attribute always which will then require you to adhere to certain constraints to help you minimize or avoid side-effects. So, meet the PURITY requirements of functions and you will find good value in their use, particularly in For(mula) Tran(slation) e.g., with expressions in code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
So based on both Steve and FortranFan's answers, setting pointers in a function are not recommended? As pointers will break the pure rules ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You can use function with pointer references, e.g. for data which you don't want to copy around, as copying those data structures might be costly. For elemental procedures, you have to use
impure elemental
then. But for the other purpose, we often use setter and getter functions, e.g.
function struct1_get_struct2_ptr (struct) result (struct2) type(struct2_t), pointer :: struct2 type(struct1_t), intent(in), target :: struct2 struct2 => struct1%struct2 end function struct1_get_struct2_ptr
for a hierarchy of data structures.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@FortranFan
Thank for this! I hadn't thought to try using an init subroutine instead of a constructor. This does work for me with both gfortran and ifort. I ended up using a slight variation on what you posted. It works but I'm wondering if it's considered legal by the standard. I've modified your example to show in general the approach I used.
module m type :: t integer, allocatable :: i integer, pointer :: ptr_i => null() character(len=10) :: id = "" contains private procedure, pass(this) :: init_t generic, public :: init => init_t procedure, public :: set_ptr end type contains subroutine init_t( this, i, id ) class(t), intent(inout) :: this integer, intent(in) :: i character(len=*), intent(in) :: id this%id = id this%i = i call this%set_ptr(this%i) ! this%ptr_i => this%i end subroutine subroutine print_addr( this ) type(t), intent(in) :: this print *, "object id: ", trim(this%id) print *, "loc(this%i) = ", loc(this%i) print *, "loc(this%ptr_i) = ", loc(this%ptr_i) end subroutine subroutine set_ptr(this, var) class(t), intent(inout) :: this integer, target, intent(in) :: var this%ptr_i => var end subroutine end module program test use m type(t) :: foo call foo%init( i=42, id="foo" ) call print_addr( foo ) end program
So basically I removed the two target attributes and then created a new subroutine for the pointer assignment that does use the target attribute for the input variable. This works perfectly in my code for Intel and GNU. Is this a reasonable alternative approach in light of the standard?
-parker
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
norton, parker wrote:.. basically I removed the two target attributes and then created a new subroutine for the pointer assignment that does use the target attribute for the input variable. This works perfectly in my code for Intel and GNU. Is this a reasonable alternative approach in light of the standard?
Unfortunately, no. As I alluded to earlier. there is a specific reason for the TARGET attribute in my example, particularly for the actual variable (such as 'mod_summary' variable in the main program in your 'summary.f90' file). Without the TARGET attribute, the standard offers no guarantee the pointer remains defined e.g., "this%ptr_i => var" in subprogram 'set_ptr' once the procedure instance completes execution i.e., when the effective argument corresponding to the dummy argument 'var' does not have the TARGET attribute. That you find Intel and gfortran/GCC compilers to work as you would like them to with your revised example in Quote #12 should be of no comfort, you cannot rely on such behavior until and unless the Fortran standard is updated to support such a situation which appears unlikely. Note, unlike some other languages such as C where there is considerable flexibility with an object to point to another object that can then hinder optimization, the Fortran standard - starting with the 90 revision - extends a restricted facility with the 2 attributes (TARGET and POINTER) to programmers given performance considerations among other matters.
Nonetheless, you may take note pointers generally and the POINTER attribute in Fortran get very tricky and if you can do without them, all the better because you and anyone else working on your code will find it much cleaner. By the way, in this situation, if your use case is really post-processing of simulation data from your "class" instances (derived type variables) based on certain criteria and/or logic (e.g., certain time intervals), you may want to consider user-defined derived-type IO (DTIO) procedures bound to your types, that way all the criteria/logic is collocated with the 'class' itself and you may find it easier to maintain and extend as your work progresses.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page