Domanda

I have to work on some legacy Fortran, although I can use the latest compilers.

The code stores enormous amounts of data in one-dimensional arrays.

For example,

PROGRAM horrible_coding
IMPLICIT EVERYTHING ! Sarcasm

REAL, DIMENSION(1000) :: data
INTEGER, DIMENSION(50)   :: info_location

! Somewhere, info is read in and stored temporarily as info_1, info_2, etc.

data(1:3) = info_1
data(4:9) = info_2
...
data(134:192) = info_n

The association between which elements in the DATA array go with which pieces of info is stored in a second array. Something like:

info_location(1) = 1
info_location(2) = 4
info_location(n) = 134

That's right. The value of each element of the info_location array refers to the first element of the data array where you can find the relevant info.

So, for example, if you want to get the data for info_7, you have to do the following:

size_of_info_7 = info_location(8) - info_location(7)
ALLOCATE(data_for_info_7(size_of_info_7))
data_for_info_7 = data(info_location(7) : info_location(7) + size_of_info_7 - 1)

By now, the sight of this insanity might have caused blood to start shooting out of your eyes so I apologize.

I would like to create object instances and store all the relevant data for each piece of info as instance data. And while I'm bringing things to 2003, I would create instance methods to get and set the instance data.

I do not want to rewrite the code but want to put this modernization on top of what's already there.

I believe I can accomplish this by making the object instance data simply pointers that point to the actual elements of the data array that contains the relevant info.

Is this a reasonable thing to do?

Can I create objects in Fortran whose instance data is predominantly pointers?

I am hesitant to begin this task without first tossing the idea around to stackoverflow.

È stato utile?

Soluzione

Can I create objects in Fortran whose instance data is predominantly pointers?

I'm not sure, what you mean, but you can definitely do something as:

type data_ptr
  real,dimension(:),pointer :: data
end type

And you can also make arrays of these types:

type(data_ptr),dimension(:),allocatable :: some_name

(can be also pointer or static, as you wish.)

Then, if original data has TARGETattribute, you can use:

some_name(i)%data => data(lower:upper)

You can also remap the pointer to different lower bounds, the process above gives it the lower bound 1.

Altri suggerimenti

I find the 'code' that you've posted a bit confusing. I expect that you know that the lines

data(1:3) :: info_1
data(4:9) :: info_2
...
data(134:192) :: info_n

are not syntactically valid Fortran (of any generation). I think that I can interpret what you are trying to tell us, but would rather not offer advice based on a (mis-)interpretation. Further, you throw entities such as info_1, info_2 into the mix without clarifying their definitions and declaration. I'm not sure whether or not info_1 is the same thing as info_location(1).

If I understand what you've posted you've got a fairly common (in old Fortran code) construction where a fixed-size array of data (helpfully called data here) which is used to store a collection of items. You then have an index array (called info_location) which contains the indexes into data at the start of each item. It is very peculiar that this index array is of type REAL, I would expect it to be INTEGER so that you could write statements such as:

data(info(3):info(4)-1))

That certainly doesn't make my eyeballs bleed, perhaps I've programmed in Fortran too long, but it looks entirely sensible to me ! One option you ought to consider is to cast info_location to INTEGER somehow and to use that as the index array. Or, you could make those casts as and when needed, writing lines such as:

data(int(info(3)):int(info(4))-1))

Personally I'd make an INTEGER index array, REALs are the wrong type for array indices.

Then, you write

So, for example, if you want to get the data for info_7, you have to do the following:

size_of_info_7 = info_location(8) - info_location(7)
ALLOCATE(data_for_info_7(size_of_info_7))
data_for_info_7 = data(info_location(7) : info_location(7) + size_of_info_7 - 1)

Since you haven't clarified exactly what info_7 or data_for_info_7 are I'm a little confused by this. If you are using implicit typing, then size_of_info_7 will be REAL and your ALLOCATE statement will fail, requiring an INTEGER for the size of the allocated object.

I suppose that data_for_info_7 is probably an allocatable array of REALs. If info_location were of type INTEGER you could simply write:

ALLOCATE(data_for_info_7, source = data(info_location(7) : info_location(8) - 1))

Vladimir F has already provided advice on using pointers to clean up your code. Another approach would be to use the ASSOCIATE construct. You could write, at the appropriate point(s) in your code, something like:

ASSOCIATE(data_for_info_7 => data(info_location(7) : info_location(8) - 1))

matching this with an END ASSOCIATE statement at the right place. This effectively defines an alias for the array section within the ASSOCIATE construct.

So, to round up:

  1. The type of the info_location array is wrong.
  2. Leaving that aside the original design, with a data array and another array of indices into it, is (certainly was) entirely reasonable.
  3. You have several options for updating the code including pointers and association.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top