Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Issue using common blocks in Fortran 2

Status
Not open for further replies.

jpcgandre

Technical User
Apr 7, 2012
2
GB
Dear All,
I'm working with fortran subroutines of a finite element analysis program. I have to share variables between the two subroutines so I'm using COMMON blocks. The problem is that only some of the variables are passed to the other subroutine, others are not.

My code is like this: First subroutine:

real knom, krot

COMMON /kVAR/ kmom, krot
SAVE /kVAR/

Second subroutine I use the same syntax. I'm controlling the results by writing kmom and krot values in each subroutine to a txt file:

write(6,*) 'I am in URDFIL', or 'I am in UFIELD'
1 KINC, kmom, krot

The results are:

I am in URDFIL 1 -16700 -2.3857285E-03
I am in UFIELD 2 -16700 -1155769886

So the value of krot is lost. Any advise is most welcome.

Thanks,

João

P.S.: I've posted this quetsion in but I haven't got any reply
 
It seems that krot was treated as real (or double precision) in the 1st subroutine and as integer in the 2nd one. Check these variable declarations in both contexts.
 
Hi jpcgandre

Note that the "kmom" variable (with "m") in the Common is undefined (integer then), while you reclare "knom" (with "n") as real. That might be the reason why some of the "krot" values are lost.
Try:
real kmom, krot



 
In any case I would recommend that you include

implicit none

in any of your subroutines or functions. This forces you to declare all your variables, but will sure spot any typos like maybe 'kmom' to 'knom'.

Are you using a fortran 77 or a later version ?

With fortran 90/95 you should replace using common blocks by using modules. With common blocks you have to make sure - and if your prog is under development this might be tricky - that the sequence and type declaration of all the variables in the common block are the same in all routines using it. Modules are far superior in handling. Using modules you declare the variables you want to share only once in the module and then use this module in all routines and functions. This ensures you have the same types of the shared variables in all your subroutines and functions. It is as easy as

Code:
module data
    real knom
    integer :: iValue = 10
    real rMatrix (100, 100)
end module

! main program
program main
    use data
    .
!   set the values for your variables 
    call sub ()
end

subroutine sub ()
    use data
    .
    .
    return
end
And if you are using Fortran77, then you should consider updating to at least Fortran 90/95 for there are morefeatures that might be extremely useful in a FEA program (derived data types, pointers).

Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
Solved:

module shared_var
implicit none
real*8 kmom, krot
save
end module shared_var

and in each subroutine:

use shared_var

Thanks!
 
One improvement (my code example was not very illuminating there: place implicit none in the routines, not in the module!

Code:
module data
    real knom
    integer :: iValue = 10
    real rMatrix (100, 100)
end module

! main program
program main
    use data
    implicit none 
    .
!   set the values for your variables 
    call sub ()
end

subroutine sub ()
    use data
    implicit none
    .
    .
    return
end

otherwise you only have it active in routines where you use this module.

Norbert


The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
I think your problem has been pointed out already above. FORTRAN variables beginning with 'K' are automatically treated as integers unless declared otherwise.
If you want floating point values, write AKROT och AKMOM instead of Krot och Kmom.

Personally I prefer to let the FORTRAN default types happen in order to avoid a mass of declarations which makes programs much harder to read and understand. I often resort to mixing languages to achieve this, writing JAHR,MONTH,JOUR instead of YEAR,MONTH,DAY !

If the variables are arrays, then in your common statements you can give them a dimension

COMMON/KVAR/AKROT(10),AKMOM(20)

but the order of the names and their dimensions must be identical in every COMMON/KVAR/
statement if you want the variables in the subroutine to correspond to the values in the calling program.

I sometimes like the COMMON/KVAR/ statement better than using modules, as it is concise. Moreover, you can pass the name of the common block as an argument in a subroutine call. It was FORTRANs way of implementing data structures before C embellished it.

For example, you can write

COMMON/KVAR/I(2), KOEFF(16), A(3,5)

in a first program that calls subroutine XYZ and
a second program that calls the same subroutine might
have written:

COMMON/LEFT/K(2), COEFF(16), ALPHA(3,5)

In the subroutine you write


SUBROUTINE XYZ(DUMMY,......)
COMMON/DUMMY/J(2),C(16),ZETA(3,5)


and then the first program does the call by

CALL XYZ(KVAR,.......)

and the second program does a

CALL XYZ(LEFT,.....)

Because the name of the common block is passed into the subroutine as an argument,
you can pass in whole data structures just by passing in the name of the common block.

You see FORTRAN always had data structures, long before C was invented!

The thing to remember about Fortran is that every argument in an argument list is passed in just as a single address which is pushed on the stack. This makes it very easy to mix Fortran and assembler. The argument can be a numeric value, the name of a subroutine or function, the name of a common block, or even, I believe, the name of a FORMAT statement.
For example I believe that you can write:
DIMENSION A(6),K(4)
.
.
200 FORMAT(6F12.5,"something", 4I2)
ASSIGN 200 TO MYFRMT
CALL XYZ(MYFRMT,A,K......)

and subroutine XXZ can write:


SUBROTUINE XYZ(IFORMT,A,K,.....)
DIMENSION A(6),K(4)
WRITE(6,IFORMT)A,K


so that the subrotuine is taking its instructions about how to format the output from outside. (This may be compiler dependent, I have done it in the past but not recently)
Not that I think that is good form either: My preference is that, as far as possible no subroutine or function should do any I/O unless that is its main purpose.

Where the new module constructs and TYPEDEF statements are useful is where you don't know what the shape of the structure is, because somebody else wrote the rountines you are calling, and there are a lot of them. Tnen it is useful just to import the declarations with a single INCLUDE statement from a file preprepared by the library writer.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top