如何复制一个文件并在其中更改一些参数?

3
我将使用Python作为接口,与我的模型中的多个Fortran文件进行交互。我想要复制一个Fortran文件多次,但在每次复制时,我都会更改描述我的模型的参数。
例如:我有以下Fortran文件。
!file.f
! This is a fortran code

!Parameters
alpha = 0.5
beta = 100
...

我想复制文件file.f多次,这样我就会有file1.f,file2.f,file3.f等等。但是,在每个文件被复制时,我希望自动更改参数alpha和beta。谢谢。
编辑:让我进一步解释一下。我正在使用Python实现数据同化(卡尔曼滤波)到已经开发好的Fortran模型中。基本上,它的工作原理是在每个指定的时间步骤中,Fortran模型停止运行,然后我将真实世界的数据集成到模型数据中,并在Python中执行此操作。然后,在集成(同化)之后,我重新运行相同的模型,但这次使用我从模型和观测数据融合得到的新参数和新的初始条件。我使用Python做所有事情,除了运行Fortran模型。

你是限制解决方案只能使用Python代码吗?还是你所说的接口是什么意思? - ardnew
4
如果这些是配置参数,为什么不让您的Fortran程序读取一个配置文件呢?这样,您就可以避免代码重复,并且只需要为每组参数调整设置文件的副本。Python 有一个很好的库 可以做到这一点。我确信在Fortran中加载类似的设置文件相对容易。 - John Lyon
3
我会只用sed来完成这个任务,用Python脚本可能过于复杂了。 - wim
如果只是几次,我会手动完成。如果超过几次,可以使用快速的Vim脚本。无论如何,编写Python解决方案(除非有你没有告诉我们的东西)似乎有些过度。此外,“fortran”标签在这里真的是多余的。 - Rook
1
也许这就是你正在寻找的解决方案:https://dev59.com/1nVD5IYBdhLWcg3wQJOT - ardnew
谢谢。我在那个网页上找到了几个有趣的实现方式。 - mikeP
4个回答

4
我认为最一致的方法是使用模板引擎。Python有很多种,通常在Web应用程序中部署。
但是,模板引擎的目的正是允许我们将大部分需要固定不变的代码作为静态文本,并通过某些特殊标记与在Python代码中生成的变量进行插值。
根据您的参数复杂程度,您甚至可以完全不需要任何单独的模板引擎,只需使用Python字符串格式化能力,就像下面的示例一样。
模板引擎可以为您提供额外的功能,例如在模板中展开循环和条件语句。
示例 - 将您的fortram模板编写如下:
!file.f
! This is a fortran code

!Parameters
alpha = %(alpha)s
beta = %(beta)s

在Python代码中,写入类似以下的内容:
template = open("fortram_template.for", "rt").read()
data = {"alpha": 0.5, "beta": 100}

with open("fortram_1.for", "wt") as output:
    output.write (template % data)

谢谢。这是一种非常好的做法。 - mikeP

2

一种Fortran的解决方案是将参数行写入单独的文本文件中,然后使用以下行在Fortran源代码中include该文件:

include 'parameters.inc'

这样,您只需重新生成参数文件即可,无需更改包含主Fortran代码的文件。


2
这是一个示例,展示了您可以做的事情。我已经将各种(alpha,beta)对放在了alpha_beta列表中。使用alpha_beta,我选择使用对位置的索引作为增加文件名的值,但您可以使用多种方法来实现这一点。这段代码很脆弱,因为它对您的.f文件假设了很多内容,但由于这是用于您自己生成这些文件的个人使用,我认为您会没问题(例如,我假设根据您提供的信息,在您的文件中只有一个以alpha开头的行实例 - 如果不是这样,最好使用正则表达式)。
alpha_beta = [(0.1, 16), (0.9, 50), (0.4, 76)]
file_name = 'file'
file_ext = '.txt'

for index, vars in enumerate(alpha_beta, start=1):
    with open(file_name + file_ext) as f:
        alpha, beta = vars
        new_file = open(file_name + str(index) + file_ext, 'w')
        for line in f:
            if line.startswith('alpha'):
                new_file.write('alpha = %s \n' % str(alpha))
            elif line.startswith('beta'):
                new_file.write('beta = %s \n' % str(beta))
            else:
                new_file.write(line)
        new_file.close()

这是一个非常好的实现。谢谢。 - mikeP

1
首先,我认为这个解决方案就像几篇评论所说的那样过于复杂。如果你不会频繁编写Fortran代码,我会选择以下两个选项之一,最好是第二个选项。
  1. 从临时输入文件中读取要使用的参数,类似于:

    !file.f
    !This is a fortran code
    
    !Parameters
    open (unit=input, file='tmp_inp.txt', action='read', iostat=ierr)
    read (input, '(...)') alpha, beta
    

    然后使用Python或sed更改临时输入文件中的值。

  2. 通过使用f2py将Fortran代码与Python进行接口处理,将参数作为参数传递给Fortran子例程。 Fortran代码如下:

    !file.f
    !This is a fortran code
    subroutine my_sub(alpha, beta)
    ...
    

    然后使用f2py编译:

    f2py -c -m my_fortran_code file.f
    

    最后在Python中调用:

    #python code
    from my_fortran_code import my_sub
    my_sub(alpha, beta)
    

这两种解决方案都不需要您重新编译任何Fortran代码,只需更改一些输入参数即可。


最好不要每次重新编译,有时这可能是一个漫长的过程。我甚至考虑使用Scheme解释模块来执行一些用户定义的操作。 - Vladimir F Героям слава

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接