Hello,
I have one .f90 file, which contains many subroutines, stacked the one after another. This file I am providing to the bifurcation software Auto-07p.
One of these subroutines seems to be called only once by the program (since it contains initial conditions), while another subroutine is called many thousands of times during execution (it contains a differential equation).
I am trying to read mathematical constants from a file once, inside the initial condition subroutine and make it available to the differential equation subroutine as well, but efficiently, so that data is not transferred at every execution, just once at the beginning. Is this possible? Or will Fortran continously read the data?
Thank you
You could store that constant into a module. And use that module in both subroutines.
I agree but would be a bit stronger, You should put the shared data in a module and use that module in the init routine (where the values are read in once) and in the consumer routines where it is only referenced. (Typically you would also put the init procedure in the module and declare the variables PROTECTED. But it is likely that sort of structure is not supported by the surrounding code, as a USE of the module would then be needed in the routine that calls init.)
I agree with the module suggestion. In case this is not possible, would this be a good opportunity to use the save
attribute? I. e.,
subroutine do_something()
real, save :: constants(5)
logical, save :: constants_read = .false.
integer :: unit
if (.not. constants_read) then
! ... initialize unit
read(unit,*) constants
constants_read = .true.
end if
! ... perform subroutine stuff
end subroutine
Thank you @vmagnin, @billlong and @ivanpribec .
Regarding the surrounding code: indeed, I have no way of telling the program it should compile the module together with the subroutines. I can of course compile my module into an -o
and -mod
file and put in the same folder. But I do not see a way to include it in the main compilation process, since this happends by the software.
Will try the save
option as well.
If you can not define the module in the same file as the subroutines, Ivan’s Save solution seems to be the solution. Testing the boolean at each call will probably have no sensible effect on speed.
I’ve faced this problem several times and I’ve used the strategies suggested previously (module or Ivan solution). The module one is nice but sometime is hard to use it, because the main code and the makefile have to be modified too deeply. Therefore, you can have another solution with a library:
- create the module, which contains the data, some subroutines for the initialisation, the calculation, …
- create simple (few lines of code) driver subroutines using the previous module: one for the initialisation, one for the calculation or one doing both (Ivan way). Those routines must be outside any module.
Then you create the library using a separate compilation so independent from the main program compilation.
Then, in the main code, you call the driver routines only (not the module ones). Therefore, for the compilation, you just need to link the library and you don’t need to “use” the .mod files of the module.
This strategy is somehow more complex, however it enables to have all modern features of the modules (and the subroutines of the module can be called as well) and the possibility to be used by linking only one library.
My personal opinion is somewhat different. Personally I prefer to pass a lot of variables to a subroutine, it really helps understanding and maintenance. If you call frequently that subroutine it is better to modify and integrate it with other subroutines to reduce the number of calls. Remember that even if you use global variables the call to a subroutine is expensive. However, if you did not work on F77 CFD codes with massively (ab)use of common blocks, you cannot understand why the use of global variables is evil.
It’ll help readers if you can explain what your situation is with your current code (e.g., are you authoring it from the ground up, or working with an existing codebase, etc.), what you can try (e.g., make certain limited changes only, or you can attempt some refactoring or even shoot for extensive modernization, etc,), and what you may or may not be to do (e.g., whether you can upgrade to current compiler versions and even commercial ones such as those by Intel and/or NAG), or you are constrained to specific older versions, perhaps open-source only such as gfortran (which version from v4.x thru’ 9.x), etc. which may then impact the feature sets from the Fortran language standard that can be employed in your code such as FORTRAN 77, Fortran 90/95, Fortran 2003, 2008, 2018 etc…
I presume you are familiar with books on Fortran since, say, year 2010 such as those by Metcalf et al., Chapman, Numrich, Hanson and Hopkins, Rouson et al.? These books (and also other resources online) point out several code design options you can consider toward the use case you mention in the original post.
Hi and thanks for this remark. Following figure illustrates the current situation:
I have access to the source code that compiles with gfortran, but would avoid making changes there, since I am a novice in Fortran and the software is rather extensive. I believe upgrading to a different compiler is possible.
I have the books of Press, Landau and Sandu, will be checking out these you suggested
As your routines are all in one Fortran source file, what is preventing you from putting the code for the module with the constants inside that same file? Put it right at the start, so the compiler processes the definitions and declarations before the subroutines that will use them. Since this will produce a single object file, there is no need to worry about extending the link step.