Fortran Functions: How Are Variables Passed Around?

In summary: END DO 6 GO TO 5 7 WRITE(1,*) "In summary, the function VA04A passes a variable F to a subroutine CALCFX, which then defines it as zero."In summary, the function VA04A passes a variable F to a subroutine CALCFX, which then defines it as zero.
  • #1
cramie10
4
1
Hi all

Just to start with I should highlight my general ineptitude with programming, so I apologize if my question is totally basic.

I have a program written (by someone else) in fortran 77. Contained within it is a call to a function which acts on a number of variables. My curiosity is about the fact that passed to the function is a variable 'F' which is not defined anywhere in the program. The function (called VA04A), calls a subroutine; CALCFX, to which it passes this variable F. F is then just defined as zero within the subroutine CALCFX, before being calculated as something else.

My question is generally how variables are passed around using functions and subroutines in fortran 77? It seems strange to me (having only worked properly with MATLAB before) that I can pass a variable to a function without defining it, for that function to then pass it to a subroutine, for that subroutine to then define it as zero anyway. Is there anywhere I can seek guidance/information on this specifically?

I've put the program and subroutine below, although I don't expect anyone to really go scouring through it.

Fortran:
      PROGRAM R55TG1
C     Fits production and decay of activity in R55 to total counts per
C      second in series of HPGe spectra
C     Written to help analyse HPGe spectra (#33 - #60) recorded on R55
C      South Balcony in September 2015
C     One half-life for all radionuclides, only TS-1 beam current
C      considered
      CHARACTER PRGNAM*6,EMIT*8,ETAD*9,A11DT*11,BET*17,ADT*23,FLNMBC*132
      DOUBLE PRECISION DMJDN,DBET
      DIMENSION ADT(100000),AI1(100000),AI2(100000),DMJDN(100000),
     1          BET(2,100),DBET(2,100),IBET(2,100),TCPS(100),
     2          TCPSFT(100),
     3          XVAR(2),EACC(2),WORK(10)
      COMMON WORK,NCLL
      COMMON/R5TG1C/AI1,NT,NL,DBET,IBET,DT,TCPS,DCPS,TCPSFT
      DATA PRGNAM,NPARAM/'R55TG1',2/
C
      CALL DATE(ETAD)
      CALL TIME(EMIT)
      OPEN(1,FILE='r55tg1-ip.txt',READONLY)
      READ(1,103) (XVAR(I),I=1,NPARAM)
C     Starting values for fit
C     XVAR(1)  Rate of production of radionuclides (per second per µA)
C     XVAR(2)  Half-life of radionuclides (minutes)
  103 FORMAT(2F10.4)
      READ(1,103) (EACC(I),I=1,NPARAM)
C     Accuracies to which parameters to be found
      READ(1,104) ESCALE,IPRINT,ICONV,MAXIT
C     VA04A parameters
  104 FORMAT(F10.4,3I10)
      READ(1,103) DCPS
C     'Uncertainty' in total counts per second
      READ(1,101) FLNMBC
C     Name of file containing TS-1 and TS-2 beam currents as function
C      of time
  101 FORMAT(A132)
      READ(1,105) LBSTRN
C     Run number of first HPGe spectrum considered - assumed numbered
C      consecutively thereafter
  105 FORMAT(I10)
      J=1
    1 READ(1,102,END=2) BET(1,J),BET(2,J),TCPS(J)
C     HPGe run beginning and end times and total counts per second
C     In A17,3X,A17 format, A17 = dd mm yy hh mm ss
  102 FORMAT(A17,3X,A17,3X,F10.4)
      J=J+1
      GO TO 1
    2 NT=J-1
C     Number of HPGe runs
      CLOSE(1)
C
      OPEN(2,FILE=FLNMBC,READONLY)
      I=1
    3 READ(2,*,END=4) ADT(I),AI1(I),AI2(I)
C     Date-and-time string, TS-1 current, TS-2 current
C     Formatted as '13-SEP-2015 23:55:44.88'    153.609    39.8766
      I=I+1
      GO TO 3
    4 NL=I-1
C     Number of lines in beam currents file
      CLOSE(2)
C
      DO 5 I=1,NL
      DECODE(23,1001,ADT(I)) A11DT,IHOUR,IMIN,SEC
1001 FORMAT(A11,1X,I2,1X,I2,1X,F5.2)
      CALL DT3JCI(A11DT,IDAY,IMONTH,IYEAR)
      CALL DMYTMJ(IDAY,IMONTH,IYEAR,MJDN)
    5 DMJDN(I)=DFLOAT(MJDN)+DFLOAT(IHOUR)/2.4D1
     1                     +DFLOAT(IMIN)/1.44D3+DBLE(SEC)/8.64D4
C     Modified Julian day number for each line of beam current file
      DO 6 J=1,NT
      DO 6 K=1,2
      DECODE(17,1002,BET(K,J)) ID,IMNTH,IY,IH,IMIN,IS
1002 FORMAT(I2,1X,I2,1X,I2,1X,I2,1X,I2,1X,I2)
      CALL DMYTMJ(ID,IMNTH,IY+2000,MJDN)
      DBET(K,J)=DFLOAT(MJDN)+DFLOAT(IH)/2.4D1
     1                      +DFLOAT(IMIN)/1.44D3+DFLOAT(IS)/8.64D4
C     Beginning and end times of HPGe spectra as mod. Jul. day no.
    6 IBET(K,J)=IRYNDD(DMJDN,NL,DBET(K,J))
C     Indexes of beginning and end times in beam current array
      DT=SNGL(8.64D4*(DMJDN(NL)-DMJDN(1))/DFLOAT(NL-1))
C     Step length (seconds)
C     Lines of beam current values assumed equally spaced in time
C
      OPEN(3,FILE='r55tg1-op.txt')
      WRITE(3,301) PRGNAM,ETAD,EMIT
  301 FORMAT(A6,4X,A9,4X,A8/)
      WRITE(3,305) (XVAR(I),I=1,NPARAM)
  305 FORMAT(2F10.4)
      WRITE(3,305) (EACC(I),I=1,NPARAM)
      WRITE(3,306) ESCALE,IPRINT,ICONV,MAXIT
  306 FORMAT(F10.2,3I10)
      WRITE(3,305) DCPS
      WRITE(3,302) NL
  302 FORMAT(/2I10)
      WRITE(3,310) FLNMBC
  310 FORMAT(A132)
      WRITE(3,304) (ADT(I),AI1(I),AI2(I),DMJDN(I),I=1,10)
  304 FORMAT(A23,2X,2F10.2,F20.6)
      WRITE(3,308)
  308 FORMAT(9X,'[first and last ten lines]')
      WRITE(3,304) (ADT(I),AI1(I),AI2(I),DMJDN(I),I=NL-9,NL)
      WRITE(3,302) NT,LBSTRN
      WRITE(3,303) (BET(1,J),BET(2,J),DBET(1,J),DBET(2,J),TCPS(J),
     1              J=1,NT)
  303 FORMAT('dd mm yy hh mm ss   dd mm yy hh mm ss   ',
     1'  Mod Jul day #  Mod Jul day #',
     2'   Tot cps'/(A17,3X,A17,3X,2F15.6,F10.2))
C
      NCLL=0
      CALL VA04A(XVAR,EACC,NPARAM,F,ESCALE,IPRINT,ICONV,MAXIT)
C
      WRITE(3,307) NCLL,F
  307 FORMAT(/I10,F10.2)
      WRITE(3,305) (XVAR(I),I=1,NPARAM)
      WRITE(3,309) (LBSTRN+J-1,TCPS(J),TCPSFT(J),J=1,NT)
  309 FORMAT(/(I10,2F10.2))
C
      STOP
      END
C
      SUBROUTINE CALCFX(N,X,F)
      DOUBLE PRECISION DBET
      DIMENSION X(2),WORK(10),
     1          AI1(100000),AN1(100000),
     2          DBET(2,100),IBET(2,100),TCPS(100),TCPSFT(100)
      COMMON WORK,NCLL
      COMMON/R5TG1C/AI1,NT,NL,DBET,IBET,DT,TCPS,DCPS,TCPSFT
C     X(1)  Rate of production of radionuclides (per second per µA)
C     X(2)  Half-life of radionuclides (minutes)
      ALMBD=ALOG(2.)/(60.*X(2))
C     Decay constant (per second)
      AN1(1)=0.
C     Initial value of zero assumed
      DO 1 I=2,NL
      DAN1=(X(1)*AI1(I-1)-ALMBD*AN1(I-1))*DT
C     dN = (production rate - decay rate) * dt
    1 AN1(I)=AN1(I-1)+DAN1
      F=0.
      DO 2 J=1,NT
      S=0.
      DO 3 I=IBET(1,J),IBET(2,J)
    3 S=S+ALMBD*AN1(I)
C     ALMBD * AN1 is activity as function of time
      TCPSFT(J)=S/SNGL((DBET(2,J)-DBET(1,J))*8.64D3)
C     SNGL((DBET(2,J)-DBET(1,J))*8.64D3) is number of seconds between
C      beginning and end of HPGe run J
    2 F=F+(TCPS(J)-TCPSFT(J))**2/DCPS**2
      F=F/FLOAT(NT-N)
      NCLL=NCLL+1
      RETURN
      END
Many thanks, I hope the question is clear.

Matt
 
Technology news on Phys.org
  • #2
For better or for worse, there is a feature in Fortran that allows you not having to declare (ahead of time) every single variable you use. Varirable F that you mentioned is not the only variable not declared ahead of time; for example, "Accuracies to which parameters to be found" preceeds a READ statement that reads values into variables ESCALE, IPRINT, ICONV and MAXIT...none of which has been prevsiously declared, either.

When using implicit typing like this, variables that start with the letters I through N are INteger; otherwise, they are REAL.

Variable F in CALCFX is not just set to zero; rather, it is initialized to zero, before being used to accumulate some sum inside the do-loop.

Anyway, nothing illegal, there; they are using implicit typing.
 
  • #3
Thanks for the answer, qsal. Very informative.

Although I do then have a couple of follow up questions.

I'm assuming that if you don't declare a variable ahead of time, the variable does still need to be declared somewhere in the program? Would FORTRAN77 throw up an error if you did not do this? (I know I should test this stuff out myself, but I haven't got a fortran77 compiler yet).

I see what you mean with F being initialized to zero. That's what I was trying to say with my poor terminology. So that leads me to ask why the variable F is passed to CALCFX at all? Is there a reason to pass that variable, or would it simply be the same if CALCFX only took the two other variables as inputs? I can't see the need for F being passed to CALCFX at all.

Thanks again.
 
  • #4
cramie10 said:
I'm assuming that if you don't declare a variable ahead of time, the variable does still need to be declared somewhere in the program?

No, if you don't declare a variable yourself, Fortran "implicitly" declares it for you. As gsal said, in that case, if the name begins with I through N, the variable is implicitly INTEGER; otherwise it's implicitly REAL.

You can turn off this behavior by putting an IMPLICIT NONE statement at the beginning of each program or subprogram. This makes Fortran behave like C, C++ etc. and throw up an error message when you don't declare a variable. I started doing this myself, about 35 years ago, in order to catch typographical errors and misspelled variable names.
 
  • #5
cramie10 said:
Thanks for the answer, qsal. Very informative.

Although I do then have a couple of follow up questions.

I'm assuming that if you don't declare a variable ahead of time, the variable does still need to be declared somewhere in the program? Would FORTRAN77 throw up an error if you did not do this? (I know I should test this stuff out myself, but I haven't got a fortran77 compiler yet).

I see what you mean with F being initialized to zero. That's what I was trying to say with my poor terminology. So that leads me to ask why the variable F is passed to CALCFX at all? Is there a reason to pass that variable, or would it simply be the same if CALCFX only took the two other variables as inputs? I can't see the need for F being passed to CALCFX at all.

Thanks again.
CALCFX is not a function, in the sense that Fortran uses that term. It is a subroutine, and although functions and subroutines share some similarities in Fortran, they also are different in some respects.

Both functions and subroutines can have a list of variables which are supplied when each routine is called. There may be variables which have their values set by the statements contained in the subroutine, which values are then returned to the calling program, like so:

CALL SUB (X1, Y1, Z1, FOUT)

The variables X1, Y1, and Z1 may be defined and initialized when SUB is CALLed, but FOUT may be initialized somewhere within SUB and then returned to the CALLing program.

A subroutine does not necessarily need to be called with any variables stated,

CALL SUB2

The subroutine SUB2 may execute some code and then return to the CALLing program when it is finished.

A Fortran FUNCTION is slightly different in concept from a Subroutine. A FUNCTION is a special kind of subroutine which expects to be supplied with some sort of data list and it returns a single value when it is finished, much like a mathematical function, f(x,y) will return a result when supplied with values of x and y.

FUNCTIONS are typed (REAL, INTEGER, etc.) just like variables, usually according to the TYPE of data returned.

The calling convention for a Fortran FUNCTION is also specialized:

YCALC = FUNC1 (X)

FUNC1 is a Fortran function which takes one data input, the variable X, does some calculations, and returns a single result, which in this case is stored in the variable YCALC. FUNCTIONS do not have to be supplied with input, but the form of this statement still must be maintained, so that the compiler doesn't get confused.

For example:

XCALC = FUNC2 ( )

FUNC2 does not need any variables passed to it in order to execute, but a set of empty parentheses is required so that the Fortran compiler doesn't confuse the identifier FUNC2 with an ordinary variable with that same name. Whatever result is calculated by FUNC2 is returned and stored in the variable XCALC.
 
  • #6
To add to the good answers already given, it is good to know that fortran uses the "pass by reference" paradigm. Every time you pas an argument to a subroutine or a function, you are actually passing a pointer to that argument; in other words, you are giving the subroutine access to the variable, not just its content.

This is contrast, for example, to C, where by default arguments are "pass by value", where the value of the variable is given to the function. To pass by reference, you need to pass explicitly the pointer to the variable.

To summarize, in your code, at the moment of
Fortran:
      CALL VA04A(XVAR,EACC,NPARAM,F,ESCALE,IPRINT,ICONV,MAXIT)
the value of F is undefined. There are 4 bytes (a REAL) in memory for F, but we have no idea what the content can be, since F hasn't been initialized.

Then, inside VA04A (for which you haven't given the code), I guess there is a
Fortran:
CALCFX(N,X,F)
and the value of F is still undefined.

Then, inside CALCFX the value of F is set. Since this is the same variable, meaning it occupies the same memory space, upon return, the value of F will be available inside VA04A, and upon return again F in the main program still contains the value as set in CALCFX. So the next statement,
Fortran:
WRITE(3,307) NCLL,F
will print out the value of F as calculated by CALCFX.
 
  • #7
Excellent answers. I can't thank you all enough! As I say, I'm new to the FORTRAN business but everyone has been perfectly explanatory and helpful.

I'll have to come back here more often :)
 
  • Like
Likes DrClaude

1. What is a Fortran function and how does it work?

A Fortran function is a subroutine or procedure that performs a specific task and returns a value. It is a block of code that can be called from other parts of a program. The function takes in input parameters, performs calculations or operations, and then returns an output value.

2. How do I declare and define a Fortran function?

To declare a Fortran function, use the "function" keyword followed by the function name and any input parameters. Then, use the "end function" statement to close the function. To define a function, add the necessary code inside the function block, including the desired output statement. Remember to use the "return" statement to specify the output value.

3. Can a Fortran function have multiple return values?

Yes, a Fortran function can have multiple return values. This can be achieved by declaring multiple output parameters in the function declaration and using them in the function definition. The function will then return all specified output values in the same order they were declared.

4. How do I call a Fortran function from my main program?

To call a Fortran function, use the function name followed by the necessary input parameters in parentheses. This can be done within the main program or within another function. The returned value can then be stored in a variable or used directly in the program.

5. Can Fortran functions be recursive?

Yes, Fortran functions can be recursive, meaning they can call themselves. This can be useful for solving problems that can be broken down into smaller subproblems. However, it is important to include a stopping condition to prevent infinite recursion.

Similar threads

  • Programming and Computer Science
Replies
6
Views
1K
  • Programming and Computer Science
Replies
22
Views
4K
  • Programming and Computer Science
Replies
6
Views
3K
  • Programming and Computer Science
Replies
2
Views
1K
  • Programming and Computer Science
Replies
14
Views
1K
  • Programming and Computer Science
Replies
4
Views
5K
  • Programming and Computer Science
Replies
8
Views
3K
  • Programming and Computer Science
Replies
4
Views
3K
  • Programming and Computer Science
Replies
6
Views
4K
  • Programming and Computer Science
Replies
2
Views
4K
Back
Top