我正在考虑将python嵌入fortran90的选项,以便为我现有的fortran90代码添加python功能。我知道可以通过使用来自numpy的f2py使用fortran90扩展python来反过来做到这一点。但是,我想在fortran中保留我的超级优化主循环并添加python来执行一些额外的任务/评估进一步的开发,然后才能在fortran中完成它,并且还可以简化代码维护。我正在寻找以下问题的答案:
1)是否存在一个已经存在的库,我可以将python嵌入到fortran中? (我知道f2py,它反过来说) 2)我们如何处理从fortran到python并返回的数据传输? 3)我们如何实现回调功能? (让我稍微描述一下场景....我在Fortran中有我的main_fortran程序,在python中调用Func1_Python模块。现在,从这个Func1_Python中,我想调用另一个函数...在Fortran中说Func2_Fortran) 4)在性能方面将python的解释器嵌入到fortran中会有什么影响....比如加载时间,运行时间,以及等等发送数据(双精度的大数组)。
非常感谢您的帮助!!
Edit1:我想通过添加一些关于我正在做的工作的更多信息来设置正确的讨论方向。我是科学计算的东西。因此,我会在双精度和浮点运算中对大型数组/矩阵进行大量工作。因此,除了fortran之外,很少有其他选择可以为我做这项工作。我想将python包含到我的代码中的原因是我可以使用NumPy在必要时进行一些基本计算,并以最小的努力扩展代码的功能。例如,我可以使用几个库来链接python和其他一些包(比如使用PyFoam库的OpenFoam)。
答案 0 :(得分:8)
我知道你想在Fortan程序中添加Python代码,而不是使用带有Fortran扩展的Python程序。我的第一条建议是不要这样做。 Fortran在数组运算方面比Python更快,但Python比Fortran更容易编写,使用OOP技术扩展Python代码更容易,Python可以访问对您很重要的库。你提到在Fortran中有一个超级优化的主循环; Fortran非常适合超级优化的内部循环。使用Numpy在Python程序中传递Fortran数组的逻辑比在Fortran中正确处理Python对象所要做的要简单得多。
当我从头开始一个科学计算项目时,我总是首先用Python编写,识别性能瓶颈,并将它们转换为Fortran。能够针对经过验证的Python代码测试更快的Fortran代码,可以更容易地显示代码是否正常工作。
由于您有现有代码,因此使用Fortran中创建的模块扩展Python代码将需要重构,但此过程应该很简单。将初始化代码与主循环分开,将循环分解为逻辑片段,将每个例程包装在Python函数中,然后您的主Python代码可以调用Fortran子例程并根据需要将它们与Python函数交错。在此过程中,您可以在Fortran的主循环中保留大量优化。 F2PY是一个相当标准的工具,所以找到可以帮助你解决任何问题的人都不会很难。
如果绝对必须让Fortran代码调用Python代码,而不是相反,最简单的方法是让Fortran代码将一些数据写入磁盘,并运行带有{{1的Python代码}或SYSTEM
。如果使用EXECUTE_COMMAND_LINE
,则可以让Python代码将其结果输出到stdout,Fortran代码可以将其作为字符数据读取;如果你有很多输出(例如,一个大矩阵),那么Python代码输出Fortran代码然后读取的文件会更有意义。磁盘读/写开销可能会对此非常重要。此外,您必须编写Fortran代码来输出数据,使用Python代码来读取它,使用Python代码再输出它,然后使用Fortran代码重新输入数据。这段代码应该直接编写和测试,但在编辑代码时保持这四个部分同步可能会变得令人头疼。
(这种方法在this Stack Overflow question)
中尝试过我无法直接将内存中的Python对象传递给Fortran。但是,Fortran代码可以调用C代码,而C代码可以嵌入Python代码。 (参见Python tutorial on extending and embedding。)通常,扩展Python(我在第1点推荐)比将其嵌入C / C ++更可取。 (参见Extending Vs. Embedding: There is Only One Correct Decision。)实现这一点将是一场噩梦,因为Python和Fortran之间的任何通信问题都可能发生在Python和C之间,或者发生在C和Fortran之间。我不知道是否有人在Fortran中实际嵌入Python,因此获得帮助将很困难。
答案 1 :(得分:5)
如果你要在Fortran中嵌入Python,你必须通过Fortran的C接口来实现;这就是ISO_C_BINDING的用途。我会警告不要嵌入Python,不是因为这样做有技术上的困难,而是因为Python(语言或社区)似乎坚决反对将Python用作从属语言。常见的观点是,您的代码当前编写的非Python语言应该被分解为库并用于扩展Python,而不是相反。所以你会看到(如此处)更多的回复试图说服你,你真的不想做你实际想做的事情,而不是实际的技术援助。
这不是燃烧或编辑或做出道德判断;这是一个简单的事实陈述。如果你试图嵌入Python,你将无法从Python社区获得帮助。
如果您需要的功能超出了Fortran语言本身所支持的功能(例如文件系统操作)和,那么您并不需要Python 和,而是希望语言比C,你可能想看看嵌入Lua。与Python不同,Lua专门用于嵌入,因此您可能面临更少的社交和技术阻力。
有许多项目integrate Fortran and Lua,我见过的最完整的项目是Aotus。作者非常敏感,整合过程很简单。
不可否认,这并没有回答原始问题(如何在Fortran 90应用程序中嵌入Python解释器),但公平地说,其他任何响应都没有。我最近使用Python作为我的便携式通用语言,在扩展我们的主要产品(用Fortran编写)时,我更愿意坚持使用它。由于上面提到的原因,我放弃了嵌入Python并尝试嵌入Lua的尝试;出于社会原因,我觉得Lua是一个更好的技术选择。这不是我的第一选择,但它是可行的,至少在我的情况下。
如果我冒犯了任何人,我会道歉;我不打算挑选一场战斗,只是将我的经验与研究这一特定主题联系起来。
答案 2 :(得分:4)
我已经尝试了几种方法来解决问题,我找到了一种可能的最佳方法。我将简要列出方法和结果。
1)通过系统调用嵌入:每次我们想从fortran访问python时,我们使用系统调用来执行一些python脚本并在它们之间交换数据。这种方法的速度受到磁盘读取,写入的限制(在这个代码的缓存级别优化时代,进入磁盘是致命的罪恶)。此外,我们需要在每次执行脚本时初始化解释器,这是一个相当大的开销。一个简单的Runge Kutta四阶方法运行300次步骤需要花费59秒才能执行。
2)通过C从Fortran转到Python:我们使用ISO_C绑定在Fortran和C之间进行通信;我们在C里面嵌入了Python解释器。我有部分工作,但同时我找到了一个更好的方法并放弃了这个想法。我仍然想为了完整性而对此进行评估。
3)使用f2py将Fortran子程序导入Python(扩展): 在这里,我们将主循环从Fortran中取出并在Python中编码(这种方法称为使用Fortran扩展Python);然后我们使用f2py(http://cens.ioc.ee/projects/f2py2e/usersguide/)将所有Fortran子例程导入Python。我们可以灵活地在任何Scientific应用程序中拥有最重要的数据,即Python中最外层的循环(通常是时间循环),以便我们可以将它与其他应用程序耦合。但是,我们还有一个缺点,即必须在Fortran和Python之间交换可能需要的数据。同样的Runge Kutta四阶方法示例需要0.372秒才能执行。
4)通过扩展模仿嵌入: 到目前为止我们已经看到了嵌入的两种纯方法(主循环保留在fortran中,我们根据需要调用python)和Extending(主循环保留在python中,我们根据需要调用fortran)。还有另一种方法,我发现这是最优化的。将主循环的部分转移到Python中会导致开销,这可能不是必须的。为了摆脱这种开销,我们可以将主循环保留在Fortran中,并将其转换为子程序而不进行任何更改,在Python中有一个伪主循环,它只调用Fortran中的主循环并且程序执行就好像它是我们的未受影响的Fortran计划。必要时,我们可以使用回调函数返回带有所需数据的python,执行脚本并再次返回fortran。在这种方法中,Runge Kutta 4th Order方法耗时0.083秒。我分析了代码,发现python解释器和加载的初始化花了0.075秒,程序只花了0.008秒(其中包括300个回调函数到python)。原始的fortran代码耗时0.007秒。因此,使用这种方法,我们几乎可以像使用python那样灵活地运行Fortran。
答案 3 :(得分:4)
使用f2py
有一种非常简单的方法可以做到这一点。编写python方法并将其添加为Fortran子例程的输入。在cf2py
钩子和类型声明中将其声明为EXTERNAL
,并将其作为返回值类型,例如REAL*8
。然后,您的Fortran代码将指向存储python方法的地址。它将是SLOW AS MOLASSES,但是对于测试算法它可能是有用的。我经常这样做(我把很多古老的意大利面条Fortran移植到python模块......)它也是在遗产fortran中使用像优化的Scipy调用这样的东西的好方法
答案 4 :(得分:3)
我开发了库Forpy
,允许您在Fortran中使用Python(嵌入)。
它使用Fortran C互操作性来调用Python C API函数。
虽然我同意扩展(在Python中使用Fortran)通常更可取,但嵌入有其用途:
除了嵌入,Forpy
还支持扩展Python。
使用f2py
,您可以在Fortran中完全编写Python扩展模块。
现有工具(如{{1}})的一个优点是可以使用Python数据类型
(例如,编写一个以Python列表作为参数的函数或一个返回Python字典的函数)。
使用现有的,可能是传统的Fortran代码通常非常具有挑战性 认为开发人员应该拥有可用于嵌入和扩展Python的工具。
答案 5 :(得分:2)
我已经成功地将Python嵌入我们的内部~500 KLOC Fortran计划cffi
。一个重要方面是不触及现有代码。该程序是用Fortran 95编写的。我使用iso_c_binding
模块编写了一个瘦的2003包装器,它只是从各个模块导入数据,获取指向这些数据的C指针和/或将Fortran类型包装成C结构,将所有内容放入单个类型/结构并发送到C函数。这个C函数恰好是一个用cffi
包装的Python函数。它将C结构解压缩为更加用户友好的Python对象,将Fortran数组包装为Numpy数组(无需复制),然后根据用户配置放入交互式Python控制台或运行Python脚本。除单个头文件外,无需编写C代码。显然有一些开销,但此功能旨在实现可扩展性,而非性能。
我会建议反对f2py。它维护得不好,严重限制了Fortran代码的公共接口。
答案 6 :(得分:1)
我为此编写了一个forcallpy库,它使用一个C层嵌入了Python表达式解释函数,并专门处理在Fortran和Python之间传递的参数,以使脚本调用尽可能容易(使用嵌入式numpy来直接在ndarrays中映射Fortran数组,使用参数名称在C / Python端知道它们的类型。
您可以在readthedocs的文档中看到一些示例。
洛朗。