移植旧的fortran程序以使用python+numpy

2024-04-24 06:35:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我应该用这个巨大的fortran77程序做研究(我最近把它移植到fortran90)。这是一个非常古老的软件,用于使用有限元方法进行建模。在

  • 这是个怪物。大约有24万条线路。在
  • 自从它在fortran77中开始使用以来,它使用了一些真正的肮脏的黑客技术来进行动态内存分配;基本上它使用C标准库中的函数,与C和Fortran混合编程。我还没有完全掌握分配是如何运作的。该程序被构建为易于用户扩展,并且用户通常需要分配一些全局可访问的数组以供以后使用。这是通过让一个内存地址数组来实现的,该数组指向动态可分配数组的起始地址。当然,地址数组的哪个元素指向哪些信息取决于用户在开始真正编程之前必须了解的约定。有两个地址数组,一个用于整数,另一个用于浮点。在
  • 所谓肮脏的黑客,我指的是不一致的黑客。例如,GNU编译器的优化算法的更新导致程序退出并随机泄漏内存。在
  • 这个节目一点也不优雅。全局变量名通常很短(3-4个字符)且晦涩难懂。当然,通过例程传递数据是通过使用公共块来完成的,其中包括所有程序开关和前面提到的数组。在
  • 该程序的用法大致类似于交互式shell,尽管它很愚蠢。首先,程序本身读取一个输入文件,然后根据选择将用户放入一个伪shell中,用户必须键入4个字符宽的命令,然后输入参数。然后解析器解析命令,并使用参数调用相应的子例程。您可能会猜想在这个伪解析器中有一个循环结构(更确切地说是goto-bonanza),它以一种比21世纪更复杂的方式包装子例程行为。在
  • 输入文件的格式是相同的(命令,然后是参数),因为它是同一个解析器。但是语法并不完全一致(我的意思是,它缺乏控制结构,一些命令导致有限状态机执行与其他命令相抵触的行为;它缺乏明确的语法),不时导致最终用户发现陷阱。用户必须通过经验了解这些陷阱;我在程序的任何文档中都没有看到它们。这是一个使用python很容易避免的问题,甚至不需要实现解析器。在

我想做的是:

  • 将程序的部分移植到python中,即那些与数值计算无关的部分。这包括
    • 使用python中的OOP方法清理和抽象API
    • 给出有意义的变量名
    • 将动态分配迁移到numpy或fortran90并丢失C部分
    • 将非数值执行迁移到python,并使用f2py包装数值对象,这样就不会造成性能损失。我有没有告诉过这个程序在当前状态下运行得很快?希望将对数值子例程的调用和I/O移植到python中不会使它慢到不切实际的程度(或者会这样吗?)。在
    • 使用python的交互式shell作为伪shell的替代。这样,最终用户就不会有任何不一致之处。前面提到的命令将被python中定义的函数简单地替换。这将允许用户实际访问数据。此外,用户将能够扩展程序,而不必深入。在

我想知道的是:

  • f2py是否合适并能胜任包装大量子例程和公共块的任务没有任何混乱?我在网上只看到了f2py的单个文件示例;我知道numpy使用它来包装LAPACK和其他东西,但是我需要保证f2py是一个足够一致的工具来完成这个任务。在
  • 有没有关于我应该遵循的总体策略的建议,或者我应该避免的陷阱。在
  • 如何在这个python包装的fortran90环境中实现一个系统,以便能够在Fortran例程中修改(分配和分配)全局可访问的数组和变量。这最好省略地址数组,并且我最好能够将口头表示注入到名称空间中。最好在python和fortran中都可以访问这些变量。在

注意事项:

  • 我可能要求的太多了,一些超出可能领域的东西。在这种情况下,请原谅我是编程这方面的初学者,请不要犹豫纠正我。在
  • 我所说的“程序”是开源的,但它是商业性的,而且许可证不允许发布,所以我决定不提它的名字。不过,你可以从第二句话和我的描述中推断出来。在

Tags: 文件用户命令程序解析器参数地址编程
2条回答

例如,如何使用多个fortran文件see this post生成f2py接口库。在

f2py可能适合您的任务,但有些陷阱可能会导致一些问题。关于f2py的一些缺陷被列出here,并总结如下:

  • 关于您的具体问题,您可能会遇到可分配数组的问题,因为f2py是为Fortran77编写的,不支持Fortran90+的许多特性(例如可分配数组)。在
  • 我还遇到了一个未记录的最大数组大小(大约400 x 200 x 20 x 20)的问题。如果我使用比f2py更大的数组,就不能生成python库。尤其是在有限元代码中传递的大矩阵可能太大而无法进行接口。因此,您将无法访问程序的Python部分中的内容。在
  • 对您有利的是f2py应该对公共块等没有问题,因为它是专门为Fortran77编写的。在
  • 在将数据通过接口传递给Fortran例程之后,如果操作正确,就不会(或只有最小的)减速。关键是每次运行时尽量减少程序Python部分的计算。这包括对数据数组的操作(shift、rotate、copy等),但是不是传递它们(因为接口是通过引用传递的)。在

作为一种选择,您应该看看Cython(也可以看到其中的Link above和链接的working example)。我想从长远来看这对你会更好。在


实施建议

这个建议是我如何结合我做过类似事情的经验来做的(见下文背景)。它应该在很大程度上独立于Python和Fortran代码的接口(f2py、Cython等)。

当然,您应该非常小心,不要改变行为,从而可能改变程序的结果。因此,在输出文件和测试文档中生成一些测试及其相应的引用,包括重现这些结果所需的所有步骤、击键、命令等,应该是您的第一步。在

在你的例子中,我会尽量少修改Fortran程序。我会尝试从Fortran代码中挖出“伪shell”,例如使它成为自己的模块,并构建一个与该模块的接口。这样,您就可以使用所有的原始Fortran代码以及来自同行的修改、错误修复和更新,甚至在将来也可以使用。关键是不要让你的代码远离原始/主流,因为在科学界,通常不是每个人都同意对源代码的重大更改,并相应地更新他们的工作流或源代码。因此,您的同行将来的工作可能不是在您的版本中进行的,而是在原始源代码中进行的,将这些更改合并到您的版本中是您自己的责任,更改得越少就越容易。在

使用这个接口,您可以在pythonshell上工作,甚至可以为它构建一个GUI,而不必担心更改原始程序中的任何内容。这样可以减少引入错误或更改原始结果的风险。因此,您的Shell/GUI将作为原始程序的包装器来工作,以简化工作流并消除不一致性。所有的“智能”和实用程序,如用户输入的错误和交叉检查、帮助页、教程/howto等都将在Python包装器中实现,Python包装器将解析这些输入,将它们转换为Fortran程序的相应命令,发送它们并等待结果。在

在你简化了程序的使用之后,我会为测试编写一些自动化程序(设置+评估),以完成你的实用程序套件。像这样,即使是新加入项目的人也能做出改变不必担心在不知不觉中改变结果。这将使您的工具能够使社区受益,从而吸引新用户,从而鼓励社区内的进一步发展。在

作为最后一步,我会用Fortran90+方法替换使用C的部分代码,以简化代码。这是一个广泛的代码库更改,需要进行大量测试,以确保在更改之前和之后,每个可能的命令组合都被检查和验证。在

这种方法还有一个好处,就是你可以让你的界面/图形用户界面开源(当然,你必须检查你的程序的许可证),只要它与Fortran程序的源代码是分开的。Fortran-Python接口必须提供,或者在使用一些简单的构建脚本加载接口时从源文件安装/生成,如本文第一个链接所示。在

对于内部数据的操作,我会编写一个单独的包装器例程,它只处理数据接口。这应该在Cython中完成,以便您能够使用可分配数组等。因为这个接口可以与“通过引用传递”一起工作,所以您应该能够使用Python(numpy)工具的完整集合来操作数组和数据。在


背景

我用我们的直升机旋翼动力学研究代码做了类似的事情。这也是一个用Fortran77编写的非常古老和庞大的程序(例如goto bonanza)。新的代码添加和修改通常在Fortran90/2003中完成。在

使用这段代码的一部分(几个子程序和模块文件),我生成了一个python库,将我们的GUI(python&Qt)连接到Fortran程序;主要用于Fortran二进制输出文件的后处理。在

我也在做类似的事情。我们没有通过C进行动态内存分配,而是使用一个具有整数索引的全局数组(也在全局范围内),但在其他方面它几乎是一样的。奇怪的,不一致的输入文件等等。在

我建议不要试图重写程序的大部分内容,不管是用python还是其他任何东西。这很费时,令人不快,而且基本上没有必要。另一种方法是,让F77代码库知道它是否编译得足够干净,以至于您愿意信任它,然后编写一个接口例程。在

我现在有一个很大的,丑陋的F77代码库,它位于一个接口后面。程序需要输入作为文本文件,因此界面的大部分工作是生成文本文件。除此之外,遗留代码被简化为一个网关例程,它接受一些参数(包括识别文本文件的方法)并返回答案。如果使用fortran2003的iso_c_绑定,则可以用c理解的格式公开接口,此时可以将它链接到任何您希望的地方。在

就现代代码(主要是优化例程)而言,遗留代码库是C接口后面的一个子例程。这比进一步修改旧代码要好得多,而且对于您的案例可能也是一个有效的策略。在

相关问题 更多 >