Run a code in fortran multiple times with different input parameters

牧云@^-^@ 提交于 2019-12-24 04:08:23

问题


I would like to run a fortran 77 program multiple times with different set of input parameters; I already made sure that output file names change for different input parameters I use, but I am not sure how I can run a program with different set of input parameters without having to go to the code each time to change the parameters.

To illustrate my question, here is a simple code.

   PROGRAM CODE
   IMPLICIT DOUBLE PRECISION (A-H, J-Z)
   COMMON / param  / radius

   radius = 2
   write(*,*) 'radius = ', radius
   write(*,*) 'the area is = ', 3.14*radius*radius

   END 

Say I want to run this code with different radiuses, and instead of having to go into the code and manually change the value, I want to have a file with different parameter choices and have it run multiple times.

Of course, there is a solution to this by creating an array of different parameter choices and looping. However, I do not want to do this, since I actually have multiple parameters I want to change for each run.

In response to one of the comments below, if I have a file with different input choices for each run, how do I have the program grab different rows for different parameter choices for each run?


回答1:


There is a "pedestrian"-type approach that I have used many times.

To avoid recompilation, a solution is to hardcode the name of the parameter file and to read the data from this file. Every run of the code must have its own copy of the parameters and so its own directory.

I give below an example for a single parameter but you can generalize it if needed. It relies on a driver script in bash.

Fortran program:

      PROGRAM CODE
      IMPLICIT DOUBLE PRECISION (A-H, J-Z)
      COMMON / param  / radius

      open(11, file='parameters.txt')
      read(11,*) radius
      close(11)
      write(*,*) 'radius = ', radius
      write(*,*) 'the area is = ', 3.14*radius*radius

      END 

bash program:

for radius in 01 02 05 10
do
RUNDIR=run_${radius}
mkdir ${RUNDIR}
echo "${radius}" > ${RUNDIR}/parameters.txt
(cd ${RUNDIR} ; ../code)
done

Compile the Fortran code:

gfortran -std=legacy -o code code.f

and execute the parametric run as:

bash parametricrun.sh
  1. What the Fortran code does: Open the file named parameters.txt and read the first entry for the value of radius.

  2. What the bash script does: For a number of values of the parameter, create a new directory, create a file named parameters.txt in that directory then execute the Fortran program code in that directory.

Comments:

  1. This can be extended to several variables, either one per line or several per line in parameters.txt, using a second loop in the bash program.

  2. If you can use a more modern version of Fortran, please mention it. There are more options there.

  3. Other languages (Python, as arclight suggests, or others) can be used for scripting. Many computing clusters use bash to run jobs, so that might be used for parametric runs (the value of radius could be passed via the job queuing system then).

  4. I used 11 arbitrarily for the file unit number. Your actual situation requires to use an available unit number for your program indeed.




回答2:


If you change to code, you need to recompile.

I don't know how complex your program is, usually it's best to write the program in such a way that it reads the values in, either from the user interface or from a file.

Check CHECK_COMMAND_ARGUMENT or Namelists for ideas how to do that.

But if you want to go down the path to recompile it every time, you can use the preprocessor to set certain parts of the code.

See this example code:

      PROGRAM area
      IMPLICIT NONE
      PRINT *, "area of circle with radius ", RADIUS, " is ",
     &         3.15159 * RADIUS**2
      END PROGRAM area

To use the preprocessor, you either have to explicitly tell your compiler to do it (gfortran -cpp or ifort -fpp for example), or you can change the extension to capital .F (or .F90 for modern Fortran) which enables the preprocessor by default.

$ gfortran -D RADIUS=2 area.F -o area
$ ./area
 area of circle with radius            2  is    12.6063604
$ gfortran -D RADIUS=20 area.F -o area
$ ./area
 area of circle with radius           20  is    1260.63599



回答3:


In the cases I've had to run a parametric analysis on codes which expect to operate on a single set of parameters, I've written a small script in Python using the Jinja2 template library to generate a large number of input files. I choose a naming convention that allows me to easily determine which input file corresponds to which input permutation to assist in post-processing the results. The specific use of Python & Jinja2 isn't as important as having a text template outside the input generation script so you can make adjustments to the generated files without editing the input generator. There are plenty of mature, simple web templating systems which can efficiently generate input text files.

The cross-reference between input parameters and file name may be as simple as an index into an array of data structures (i.e. a hash or dict). I try to use something more meaningful and to add descriptive comments to the generated input (assuming the input format allows comments...)

In my case, I may be using code that I can't recompile without going though a month-long QA cycle so it's much cheaper for me to write the parametric variation code as a separate script than to integrate it into my Fortran code.

The other reason I tend to write the parametric analysis code in Python is because it's much easier than writing complex input processing in Fortran. Being able to use numpy to generate linear, logarithmic, or other variation patterns (e.g. Chebyshev nodes) is so much easier than trying to do it in Fortran.

Standard disclaimer: my operating environment and use cases are probably very different than yours so this technique may not be appropriate. I'm just pointing out that it is an option with several advantages, depending on your environment.




回答4:


the command line argument approach

  implicit none
  real r
  character*30 arg
  integer ios
  if(command_argument_count().eq.0)then
! default for no argument
    r=1. 
  else
     call get_command_argument(1,arg)
     read(arg,*,iostat=ios)r
     if(ios.ne.0)then
        write(*,*)'error expected number arg got ',arg
        stop
     endif
  endif
  write(*,*)r
  end

note for ancient compilers you should used iargc and getarg instead. The purists will note these are non standard f77, however they are commonly available in many compilers.

typical python script to loop over a list of arguments:

import os
for r in (1.2,6.6): os.system('fortran_program %g'%r)

of course you should use whatever script language you are comfortable with. I like a "high level" language since I inevitably seem to end up doing calculations in the script.



来源:https://stackoverflow.com/questions/46650571/run-a-code-in-fortran-multiple-times-with-different-input-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!