I have a file with parameters used for sizing arrays. Here is a part of it
integer, parameter :: MS_ = 21 ! maximum number of bond series, must be odd!
integer, parameter :: MS_ = 257 ! maximum number of bond series
I have been given the task to try and change this so that we can just have one executable for both applications. A run time input parameter is passed to determine which case is running so the proper subroutines are called.
I have been trying to setup parameters that allow the element of a 2 value array in the above case by doing something like this
integer, parameter MS_(2) = [257,21]. these statements are in a module that has 2 parameters assigned with values 1 and 2 and an integer called run type.
My idea was having the main routine use this module and set runtype to one of the 2 parameters which would evaluate to one of the 2 elements of the array.
I am getting errors 7974 and 6530 for each entry used in my new module.
Replace the parameter of "maximum number of bond series" with a variable holding the actual "number of bond series" .AND.
In places where you have static data (module or common), make the arrays allocatable.
In places where you use local data, and seeing that these arrays are relatively small, make the arrays automatic.
module GlobalData integer :: NBS ! number of bond series, defined at run time ... REAL, allocatable :: BondSeries(:) ! bond series, allocated, then defined at run time ... end module GlobalData subroutine init() use GlobalData ... NBS = GetNumberOfBondSeries() allocate(BondSeries(NBS)) ... end subroutine init subroutine DoWork(...) use GlobalData implicit none ... ! argument declarations real :: TempArray(NBS) ! automatic array ... end subroutine DoWork
Thanks for the answer. That will only help partly. Some of the parameters are used to derived types that are lumped together to create a new derived type and also other arrays can be 100,000 elements long. I was hoping to do all of this in the main routine and use a module that will have the values in it so the parameters can be used in all of the different cases.
Currently the hard coded values are their to set the maximum size of an array and test to see if the array is going to go over the limit so an error can be generated for the user. At current they do not want me to do actual allocating yet. That will be the next iteration, if we get their.
So is there a way that I can actually maintain these limits.
>>At current they do not want me to do actual allocating yet.
Let me guess, when your application was written, memory was tight (and you did not have allocatable arrays). The system then may have had a few MB to work with. Today, just about all systems (desktops, notebooks) have a few GB, or 1000x more memory. (servers may have 10,000-100,000x more).
You could simply pick a significantly large number
integer, parameter :: MS_ = 257*100 ! maximum number of bond series
*** With the caution that most compiler generated linker object code have an upper limit of 2GB for static data (not sure about uninitialized data). While there are ways on Linux to overcome this, there isn't on Windows. Considering this, at some point you are going to have to "bite the bullet" and migrate to using allocatable arrays.
User defined types can contain allocatable arrays. This does have a drawback that you cannot write a blob of a UDT that may contain lesser than the full complement of arrays containing less than MS_ numbers of elements. Note, if the UDT has more than one such array, you cannot write as a shortened blob.
Also note, Fortran supports Defined I/O Procedures that (when necessary) you can use for reading and writing UDTs.
There's a bit of a conceptual gap in the response in #3.
At the moment, you have a constant (something that is known at compile time) that is used in places where a constant is required.
You want to change to something that is fundamentally not a constant - the value isn't going to be known until runtime (a constant array indexed by a variable is not a constant - if you vary the index - you get a varying result; constants don't vary). You are going to need to adapt the code such that the places that currently require a constant (as indicated by the reported errors), no longer require a constant.
That means you need to start using allocatable and automatic variables, as Jim describes in #2. For derived type definitions, you may need allocatable components or length parameterized types.
If you show some examples about where the constant is used, then more advice can be provided about how to modify the code so that a constant is no longer required. Fundamental to this will be a change from "everything known and acted on about array size at compile time", to "during execution, program figures out array size and then takes executable actions to set the relevant arrays up".
Here are some examples of how these constants are used.
character*32 series_label(ms_) ! so string search can look at adjacent locations
type (b$$series) series(ms_)
type (b$$group) group(mtbg_)
type (b$$bond) bond(mb_)
type (b$$fee) fee(mbfee_)
type (b$$fee) insur(mbfee_)
type (b$$cost) coi(mbfee_)
type (b$$cost) spread(mbfee_)
type (b$$deposit) deposit(mbfee_)
type (override$_data) over
if(itestgrp .gt. mbg_) then
As you can see these constants are used in a number of different ways.
I am trying to go from compile constants to runtime values (only 2 values exist for each constant), with out a major rewrite. I am also working on more of a rewrite, but they want that for farther down the road in time.
Well apart from " if(itestgrp .gt. mbg_) then" all the rest would need to be allocatable arrays if you want the vars to be set at run time rather than parameters set at compile time. If you want to maintain the same behaviour then every time you declare a new variable of type b$$s you would need to then allocate its components using the size variables. Also you need to read up on "allocate left hand side" which might cause some unexpected behaviour in code that was probably written before that language concept existed.