运行 多次使用不同输入参数的 Fortran 代码

Run a code in fortran multiple times with different input parameters

我想 运行 使用不同的输入参数集多次执行 Fortran 77 程序;我已经确定输出文件名会随着我使用的不同输入参数而改变,但我不确定我如何 运行 一个具有不同输入参数集的程序,而不必每次都转到代码来更改参数.

为了说明我的问题,这里有一个简单的代码。

   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 

说我想 运行 这段代码有不同的半径,而不是必须进入代码并手动更改值,我想要一个具有不同参数选择的文件并拥有它 运行多次。

当然,可以通过创建一个包含不同参数选择的数组和循环来解决这个问题。但是,我不想这样做,因为我实际上有多个参数,我想为每个参数更改 运行.

作为对以下评论之一的回应,如果我有一个文件,每个 运行 都有不同的输入选择,我如何让程序为每个 [=22= 的不同参数选择抓取不同的行]?

如果改成代码,需要重新编译

我不知道您的程序有多复杂,通常最好以从用户界面或文件中读取值的方式编写程序。

检查 CHECK_COMMAND_ARGUMENT or Namelists 了解如何做到这一点。

但是如果你想每次都重新编译它,你可以使用预处理器来设置代码的某些部分。

查看示例代码:

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

要使用预处理器,您必须明确告诉编译器这样做(例如gfortran -cppifort -fpp),或者您可以将扩展名更改为大写.F (或 .F90 对于现代 Fortran)默认启用预处理器。

$ 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

在我不得不 运行 对期望对一组参数进行操作的代码进行参数分析的情况下,我使用 Jinja2 在 Python 中编写了一个小脚本模板库生成大量输入文件。我选择的命名约定使我能够轻松确定哪个输入文件对应于哪个输入排列,以协助 post- 处理结果。 Python & Jinja2 的具体使用并不像输入生成脚本之外的文本模板那么重要,因此您可以在不编辑输入生成器的情况下对生成的文件进行调整。有很多成熟、简单的 Web 模板系统可以有效地生成输入文本文件。

输入参数和文件名之间的交叉引用可能就像数据结构数组(即散列或字典)的索引一样简单。我尝试使用更有意义的东西并向生成的输入添加描述性注释(假设输入格式允许注释...)

在我的例子中,我可能使用的代码如果不经过长达一个月的 QA 周期就无法重新编译,所以对我来说,将参数变体代码编写为单独的脚本比将其集成到脚本中要便宜得多我的 Fortran 代码。

我倾向于在 Python 中编写参数分析代码的另一个原因是因为它比在 Fortran 中编写复杂的输入处理要容易得多。能够使用 numpy 生成线性、对数或其他变化模式(例如 Chebyshev 节点)比尝试在 Fortran 中更容易。

标准免责声明:我的操作环境和用例可能与您的非常不同,因此此技术可能不合适。我只是指出它是一个具有多项优势的选项,具体取决于您的环境。

有一种"pedestrian"类型的方法我已经用过很多次了。

为了避免重新编译,一个解决方案是硬编码参数文件的名称并从该文件中读取数据。每个 运行 代码都必须有自己的参数副本,因此有自己的目录。

我在下面给出了单个参数的示例,但如果需要,您可以对其进行概括。它依赖于 bash.

中的驱动程序脚本

Fortran 程序:

      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 程序:

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

编译 Fortran 代码:

gfortran -std=legacy -o code code.f

并执行参数 运行 为:

bash parametricrun.sh
  1. Fortran 代码的作用:打开名为 parameters.txt 的文件并读取半径值的第一个条目。

  2. bash 脚本的作用:对于参数的多个值,创建一个新目录,在该目录中创建一个名为 parameters.txt 的文件,然后执行 Fortran程序code那个目录。

评论:

  1. 这可以扩展到多个变量,在 parameters.txt 中每行一个或每行几个,在 bash 程序中使用第二个循环。

  2. 如果您可以使用更现代的 Fortran 版本,请提及。还有更多选择。

  3. 其他语言(Python,如 arclight 所建议的,或其他语言)可用于编写脚本。许多计算集群使用 bash 到 运行 作业,因此这可能用于参数化 运行s(半径的值可以通过作业排队系统传递)。

  4. 文件单元号我随便用了11。您的实际情况确实需要为您的程序使用可用的单元号。

命令行参数方法

  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

请注意,对于古老的编译器,您应该改用 iargcgetarg。纯粹主义者会注意到这些是非标准的 f77,但是它们在许多编译器中通常可用。

循环参数列表的典型python脚本:

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

当然,您应该使用您熟悉的任何脚本语言。我喜欢 "high level" 语言,因为我似乎不可避免地要在脚本中进行计算。