For Programmers: Free Programming Magazines  


Home > Archive > Fortran > October 2004 > Any fortran 90/95 wizards out there? Need help









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Any fortran 90/95 wizards out there? Need help
Mix1009

2004-10-18, 4:00 pm

Hi,
I have a programming task that I've been unable to solve using
standard
fortran 90/95 language (although I was able to get it to work using
Cray-style
pointers. Can anyone think of an approach?

I'm trying to write a general-purpose search routine to convert one
set of
codes to another. The conversion table is located on a tab-delimited
file.

The overall approach is:
On first call, determine the length of the old code, length of the
new
code, and number of codes and dynamically allocate, fill, and sort
the
conversion table.
On first and subsequent call, do a binary search on the table in
memory to obtain the
conversion information.

The problem I've run into is the dynamically allocated table
disappears
between calls. When I add the SAVE attribute, I get an error message
(using the Intel Fortran compiler).

Any help will be greatly appreciated,

Ron

etQpredX@hotmail.com
r e m o v e the Q and X






Subroutine Convert(FieldOld,FieldNew,FilNam)
Character(*) FieldOld,FieldNew,FilNam
c
c Stub to allow dynamic allocation of table
c (since the length of passed parameters
c must be known at time of routine entry)
c
LO = Len(FieldOld)
LN = Len(FieldNew)
Call Convert2 (FieldOld,FieldNew,FilNam,LO,LN)
Return
End
c
c The real subroutine
c

Subroutine Convert2 (FieldOld,FieldNew,FilNam,LO,LN)
Character(*) FieldOld, FieldNew
Character(*) FilNam
Character(LO), Allocatable :: OldFieldTable(:)
Character(LN), Allocatable :: NewFieldTable(:)
c NOTE: Character(LN), Allocatable, Save :: NewFieldTable(:)
c gets an error
Data iFTS/1/ ! First time switch
c
If (iFTS.eq.0) go to 300 ! Check for first time procedure
iFTS = 0
c
c Count number of records
Call CountNumberOfRecords (NumRec)
c
Allocate (OldFieldTable(NumRec)) ! Allocate memory
Allocate (NewFieldTable(NumRec)) ! Allocate memory
c
c
c Load Table
c
Call LoadTable(NumRec, FilNam, OldFieldTable, NewFieldTable)
c
c Sort table
c
Call CSORT (OldFieldTable,NewFieldTable,NumRec)
c
c Do binary search
c
300 Continue
c
Call BSearch (NumRec, IndexMatch, FieldOld, OldFieldTable)
FieldNew = NewFieldTable (IndexMatch)
c
c
Return
End
Rich Townsend

2004-10-18, 4:00 pm

Mix1009 wrote:

<snip>

> Subroutine Convert2 (FieldOld,FieldNew,FilNam,LO,LN)
> Character(*) FieldOld, FieldNew
> Character(*) FilNam
> Character(LO), Allocatable :: OldFieldTable(:)
> Character(LN), Allocatable :: NewFieldTable(:)
> c NOTE: Character(LN), Allocatable, Save :: NewFieldTable(:)
> c gets an error


I'm not sure of the particular part of the Fortran standard that
prohibits this; but I'm guessing that your problems come from the fact
that newFieldTable has a variable character length LN. If this array is
SAVEd over subroutine calls, what happens then Convert2() is called with
a different value of LN than previously? That there is ambiguity here,
is a sure sign that you are doing something counter to the standard.

Two possible fixes come to mind:

a) use a constant for the character length.

or

b) declare NewFieldTable to be of type(VARYING_STRING), as defined in
Part II (Varying length character strings) of the Fortran 95 standard.
If you decide to do this, you will need an implementation of the
ISO_VARYING_STRING module defined in Part II; you can download one such
implementation (written by myself, bug reports welcome!) from:

http://www.fortran.com/fortran/iso_varying_string.f95

cheers,

Rich

--
Dr Richard H D Townsend
Bartol Research Institute
University of Delaware

[ Delete VOID for valid email address ]
Richard E Maine

2004-10-18, 4:00 pm

etpred@nocharge.com (Mix1009) writes:

> The problem I've run into is the dynamically allocated table
> disappears between calls.


Yep. Non-saved things do that. With allocatable, they are *REQUIRED*
to do that - it isn't up to the compiler.

> When I add the SAVE attribute, I get an error message


General advice. When reporting an error message, quote what it says
instead of just saying "an eror message". In this case, I can deduce
the problem anyway, but keep the advice in mind for the future.

> Subroutine Convert2 (FieldOld,FieldNew,FilNam,LO,LN)

....
> Character(LO), Allocatable :: OldFieldTable(:)


The reason you get an error message when you add SAVE is (presumably)
because OldFieldTable is an automatic variable - that is it depends on
dummy arguments (LO). You can't have something that is both automatic
and saved - they are contradictory. Automatic things are allocated
with each subroutine call. The problem is that, in general, LO might
be different from one call to another, in which case there would be a
conflict between the saved data and the new declaration. True, your
particular calls might happen to retain the same value of LO, but
neither the compiler nor the standard treats that as a special case -
it has to make sense in general.

There is a fine solution in f2003. F2003 allows allocatable character
length, so you could declare

Character(:), Allocatable :: OldFieldTable(:)

Now oldfieldtable is no longer automatic (we got rid of the dependence
on LO - at least we moved it out of the declaration, which is what counts).
Then specify the length in the allocate as

Allocate (character(LO):: OldFieldTable(NumRec))

But that syntax for allocate is new to f2003; probably won't work in
current compilers (unless they happen to have already implemented that
f2003 feature - none have to my knowledge).

For now, only 2 solutions occur to me off the top of my head. Neither
seems particularly satisfactory, though probably either could be made
to work.

1. Use a hard-wired character length instead of a dynamic one. You
can still make the numrec dynamic - that's not the problem.

This will work if you can specify some length that is both large
enough so that it will work for all practical cases and small
enough so that the memory cost won;t be excessive.

You can still carry around the LO (and LN) variables so that you
can refer to the substrings (1:LO) and (1:LN) when needed.

2. Use an array of characters instead of a character string. In your
case, you have an array of strings, so turn that into a rank 2 array
of characters (each of hard-wired length 1). Allocating arrays is
fine in f90/f95. It is allocating character length that you can't
do until f2003, so turn the character length into an array.

While it can certainly work, this has the divantage that you can't
use many of the handy string intrinsics on arrays of character. Also,
you'd have to correspondingly change declarations elsewhere, which might
be a bother, depending how many places that is.

Oh yes... in writing the second option above, a 3rd one ocurred to me..

3. Allocate as a rank 2 array of character*1, as in option 2. Then use
sequence association to pass this allocated array as an actual argument
to a dummy declared as a rank 1 array of strings. In order for the
sequence association trick to work, the dummy has to be declared with
adjustable array bounds and character length - do not use * as a
character length and do not use assumed shape. I.e. the dummy
declaration has to look something like

Character(LO) :: OldFieldTable(numRec)

where LO and numRec are both dummy args; you'd have to add LO (and LN)
as args to a few of your lower-level routines.

I consider this a bit of a hack, but it ought to work. Note that it
does mean that the oldfieldtable is still a rank 2 array in the
subroutine that allocate it - only in lower-level subroutines can you
look at it as a rank 1 array of strings. Well... you might be able
to hack up a trick with pointers, but that gets pretty subtle...enough
so that I'd have to think a while to be sure it could work in this
case.

A lot simpler to just rewrite the one statement setting newfieldrec;
that looks to be the only one really hit by this in the code you showed.

--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain | experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
Richard E Maine

2004-10-18, 4:00 pm

Rich Townsend <rhdt@barVOIDtol.udel.edu> writes:

> b) declare NewFieldTable to be of type(VARYING_STRING)...


I forgot to mention that option.

I might note that it is a variant of the general option of using an
array of characters to replace a character string, but it has extra
"stuff" (to use a technical term :-)) wrapped around it so that most
of the nice character operations do sensible things. And implementors
(such as Rich Townsend) have done the work involved in that extra
stuff.

--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain | experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
glen herrmannsfeldt

2004-10-18, 4:00 pm



Richard E Maine wrote:

> etpred@nocharge.com (Mix1009) writes:


[color=darkred]
> Yep. Non-saved things do that. With allocatable, they are *REQUIRED*
> to do that - it isn't up to the compiler.


I was going to ask last w if allocatable arrays could be
allocated in one subroutine, and deallocated in a called subroutine,
or the other way around. It would seem from that that the second
case doesn't work.

For discussion purposes only, and not to get into any arguments,
PL/I CONTROLLED (like allocatable) can be allocated/deallocated
at any level (of subroutine nesting). Sort of like C's
malloc/free, except that dimension information is also included.

The question about contiguous allocation came from forgetting
how assumed size and assumed shape work, and which one allocatable
would be more like.

-- glen

Steve Lionel

2004-10-18, 4:00 pm

On 18 Oct 2004 10:17:37 -0700, etpred@nocharge.com (Mix1009) wrote:

>The problem I've run into is the dynamically allocated table
>disappears
>between calls. When I add the SAVE attribute, I get an error message
>(using the Intel Fortran compiler).


The particular issue you ran into is that the variable in question is
"automatic" diue to the character length being dependent on a dummy argument.
Automatic variables cannot be SAVEd. Fortran 95 doesn't provide exactly what
you want, which is a persistent array of run-time length character elements.
I'll let others offer suggested alternatives.


Steve Lionel
Software Products Division
Intel Corporation
Nashua, NH

User communities for Intel Software Development Products
http://softwareforums.intel.com/
Intel Fortran Support
http://developer.intel.com/software/products/support/
Richard E Maine

2004-10-18, 4:00 pm

glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:

> Richard E Maine wrote:


>
> I was going to ask last w if allocatable arrays could be
> allocated in one subroutine, and deallocated in a called subroutine,
> or the other way around. It would seem from that that the second
> case doesn't work.


Non-sequitur (I don't see the connection).

The answer to your question is that yes, an allocatable can be
allocated in one subroutine and deallocated in a called one, or
the other way around. Both capabilities require the allocatable TR
(or f2003) in order to allow a dummy argument to have the allocatable
attribute. Or you can do it with the allocatable in a module or
with host association; those work even in f90 without the TR.

My "non-saved things do that" is a severe abbreviation of the actual
conditions. Maybe you were taking it a bit more globally than I
intended. Then I'd see the connection (but my statement isn't valid
in the relevant contexts). To be more complete, I'd need to qualify
it as something like "local" non-saved things and the define what I
meant by local. SAVE never applies to dummy arguments, and things are
a bit more complicated for variables in modules. So no, an
allocatable dummy argument doesn't go away when you return just
because it is non-saved (and you can't declare a dummy to be saved).

--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain | experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
glen herrmannsfeldt

2004-10-18, 4:00 pm



Richard E Maine wrote:

> glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:


(snip)

> The answer to your question is that yes, an allocatable can be
> allocated in one subroutine and deallocated in a called one, or
> the other way around. Both capabilities require the allocatable TR
> (or f2003) in order to allow a dummy argument to have the allocatable
> attribute.


For the allocatableness (probably not a word) to be passed to the
called subroutine? Does the caller need to know if the dummy
has the allocatable attribute?

> Or you can do it with the allocatable in a module or
> with host association; those work even in f90 without the TR.


> My "non-saved things do that" is a severe abbreviation of the actual
> conditions. Maybe you were taking it a bit more globally than I
> intended. Then I'd see the connection (but my statement isn't valid
> in the relevant contexts). To be more complete, I'd need to qualify
> it as something like "local" non-saved things and the define what I
> meant by local. SAVE never applies to dummy arguments, and things are
> a bit more complicated for variables in modules. So no, an
> allocatable dummy argument doesn't go away when you return just
> because it is non-saved (and you can't declare a dummy to be saved).


If I understood a previous post, he wanted to allocate and initialize
an array in a subroutine, and use it in the same routine called
later. So, by adding it as a dummy argument and calling it with
the appropriate (but otherwise unused) argument it would stay allocated?

-- glen

Richard E Maine

2004-10-18, 8:56 pm

glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:

> Richard E Maine wrote:
>


>
> For the allocatableness (probably not a word) to be passed to the
> called subroutine? Does the caller need to know if the dummy
> has the allocatable attribute?


Yes. Specifically, the interface of th ecalled subroutine needs to
be explicit (and that's why - so that the caller knows this.)

> If I understood a previous post, he wanted to allocate and initialize
> an array in a subroutine, and use it in the same routine called
> later. So, by adding it as a dummy argument and calling it with
> the appropriate (but otherwise unused) argument it would stay allocated?


Yes. Exactly.

--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain | experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
glen herrmannsfeldt

2004-10-18, 8:56 pm



Richard E Maine wrote:

> glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:


(snip)

[color=darkred]
> Yes. Specifically, the interface of the called subroutine needs to
> be explicit (and that's why - so that the caller knows this.)


OK, same as PL/I.

[color=darkred]
> Yes. Exactly.


OK, PL/I has CONTROLLED INTERNAL which go out of scope when
the routine ends. I believe the user is responsible for the
FREE before return, though. CONTROLLED EXTERNAL is the global
version, which stays allocated, and can be used from other routines
with the same declaration. STATIC EXTERNAL is like Fortran COMMON.

-- glen

Aidan

2004-10-22, 3:56 am

Mix1009 <etpred@nocharge.com> wrote:

> I'm trying to write a general-purpose search routine to convert one
> set of codes to another. The conversion table is located on a tab-delimited
> file.


I know this is an answer to your actual question .. but isn't this a
job for a hash table?

Populate your hash table with the oldcode -> newcode mappings and zip
through the data you need to change. Voila!

In this case, is something like perl/python/tcl more appropriate? If
you do need to bury this in some larger fortran project then I have
a hash table module you could try using (a translation of Bob Jenkins'
C code from http://burtleburtle.net/bob/hash/evahash.html)

Cheerio

Aidan


Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com