Numerical Recipes Forum  

Go Back   Numerical Recipes Forum > Obsolete Editions Forum > Fortran 90 Programming with NR

Reply
 
Thread Tools Display Modes
  #1  
Old 08-25-2008, 08:22 AM
paus paus is offline
Registered User
 
Join Date: Aug 2008
Posts: 2
getarg

Hello,

I want to use getarg to define a global variable in a module (afterwards I want to execute this fortran compiled program using as second argument a number (integer)). I tried:

MODULE global_vars
CHARACTER(len=3) :: BUFFER
INTEGER :: ntimes

contains
CALL getarg(2,BUFFER)
READ(BUFFER,*) ntimes

END MODULE global_vars


but this fails given a message:

fortcom: Error: /dirX/program.f90, line 66: The statement following a CONTAINS is not a function-stmt or a subroutine-stmt.
CALL getarg(2,BUFFER)


why is this the case, and how to bypass this?

Thanks for any help.
Reply With Quote
  #2  
Old 08-25-2008, 03:12 PM
davekw7x davekw7x is offline
Registered User
 
Join Date: Jan 2008
Posts: 453
Quote:
Originally Posted by paus View Post
I want to use getarg to define a global variable in a module...

fortcom: Error: /dirX/program.f90, line 66: The statement following a CONTAINS is not a function-stmt or a subroutine-stmt.
CALL getarg(2,BUFFER)

.
Modules can contain variables and functions and subroutines, not just any old code. How would your main program invoke that code unless the code appeared in a subroutine or function that was contained in the module?

I'm not sure what you have in mind (getarg() is a built-in function; it doesn't define anything), but here's something to try. It works for me with GNU gfortran (Version 4.1.2)
Code:
        MODULE global_vars
        CHARACTER(len=3) :: buffer
        INTEGER :: ntimes
        END MODULE global_vars

        PROGRAM test_globals
        USE global_vars

        write(*, '("Number of arguments = ",I0)') iargc()
        if (iargc() .lt. 2) goto 998

        call getarg(2,buffer)
        read(buffer,*, ERR=999) ntimes
        write(*,'("ntimes = ", I0)') ntimes
        stop

998     print *,"Insufficient input."
        stop
999     print *,"Bad input."

        END PROGRAM test_globals
Here are a few runs:

Code:
$./test_globals
Number of arguments = 0
 Insufficient input.
Code:
$./test_globals 111111 222222 333333
Number of arguments = 3
ntimes = 222
Code:
$./test_globals 11z 22 333
Number of arguments = 3
ntimes = 22
Code:
$./test_globals 11 22.2 33
Number of arguments = 3
 Bad input.
Regards,

Dave
Reply With Quote
  #3  
Old 08-26-2008, 05:22 AM
paus paus is offline
Registered User
 
Join Date: Aug 2008
Posts: 2
Main idea

The main idea is to use a script that feeds a variable through execution of this fortran executable, something like:

execute fortran_file arg1 arg2

where arg1=filename
and arg2=ntimes (a number)

I want to define ntimes in a general way, so everywhere in the program it can be used. I thought making a module would be a neat way, but I guess this is harder as I thought.

I can do it in the way you suggested, but since I also use ntimes in subroutines, it would be more practical to create a global variable ... otherwise I would have to CALL getarg in all subroutines as well.

Any suggestion would be great.

Thanks.
Tim
Reply With Quote
  #4  
Old 08-26-2008, 10:01 AM
davekw7x davekw7x is offline
Registered User
 
Join Date: Jan 2008
Posts: 453
Quote:
Originally Posted by paus View Post
... it would be more practical to create a global variable ...
Any suggestion would be great.
The traditional way to make global variables in Fortran (when it was spelled FORTRAN, and didn't have numbers like II, IV, 77, 90, etc.) was to use common blocks. Use of named blocks could make selectively "global" variables that were available in any subprogram that used that named block.

Use of a module can make variables that are "somewhat global" in a way similar to the methodology of using common blocks. That is, the variables are available to any subprograms that use that module. So you could have a function or subroutine (that uses that module) read in the variables and go from there.

Modules can also contain subprograms that will be available to any other part of the program that uses that module. By compiling modules separately, they can be linked with other parts of programs under development without having to recompile the module each time.

Whether you use common blocks of modules to give you "global" variables, I offer the following opinion:


[opinion]
Gratuitous use of global variables, in general is frowned on (by many programmers and analysts) in modern times.
Here's the drill:
Pass variables to subprograms as parameters.
Declare everything explicitly in each part of the program.

Among other things, this makes debugging more straightforward, since it decreases the likelihood that simple typos (misspelling variable names in subprograms, for example) can cause disastrous side effects.
[/opinion]

It's just an opinion. Some still cling to the mid-20th-century notion (when mainframes had a few tens of thousands of words of memory and CPU instruction cycle times were measured in microseconds) that using globals is, somehow, more "efficient" than passing parameters.

For an example without globals:

Code:
      FUNCTION getinputs(iname, inumber)
        IMPLICIT NONE
        INTEGER          :: getinputs
        CHARACTER(LEN=10):: iname
        INTEGER          :: inumber
        CHARACTER(LEN=10):: buffer

        IF (iargc() .LT. 2) GOTO 998

        CALL getarg(1,iname)
        WRITE(*,'("getinputs: file name is ",A)') iname

        CALL getarg(2,buffer)
        READ(buffer,*, ERR=999) inumber
        WRITE(*,'("           iterations = ", I3)') inumber
        getinputs = 1
        RETURN

998     WRITE(*, '(/"Insufficient input."/)')
        getinputs = 0
        RETURN

999     WRITE(*, '(/"Bad input."/)')
        getinputs = 0
        RETURN
      END FUNCTION getinputs
          
        
      SUBROUTINE f1(fnam, fnum)
        IMPLICIT NONE
        CHARACTER(LEN=10):: fnam
        INTEGER          :: fnum
        WRITE(*,'("f1: fnam  = ",A, ", fnum    = ", I3)') fnam,fnum
      END SUBROUTINE

      SUBROUTINE f2(fname, fnumber)
        IMPLICIT NONE
        CHARACTER(LEN=10):: fname
        INTEGER          :: fnumber
        WRITE(*,'("f2: fname = ",A, ", fnumber = ", I3)') fname,fnumber
      END SUBROUTINE

      PROGRAM test_args
        IMPLICIT NONE

        INTEGER          :: getinputs

        CHARACTER(LEN=10):: filename
        INTEGER          :: iterations

        IF (getinputs(filename, iterations) .NE. 0) THEN
            CALL f1(filename,iterations)
            CALL f2(filename,iterations)
        END IF
        STOP


        END PROGRAM test_args

Here's a run (as compiled with either GNU g77 or GNU gfortran)
Code:
$./test_args data.txt 4
getinputs: file name is data.txt  
           iterations =   4
f1: fnam  = data.txt  , fnum    =   4
f2: fname = data.txt  , fnumber =   4
Here's another:
Code:
$./test_args data.txt 4z
getinputs: file name is data.txt  

Bad input.


I mean, there are times and places where globals may be appropriate, but...

Oh, well: Chacun * son goût!


Regards,

Dave

Last edited by davekw7x; 08-26-2008 at 02:24 PM.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 04:36 PM.


Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.