简体   繁体   English

将python嵌入到fortran 90中

[英]Embed python into fortran 90

I was looking at the option of embedding python into fortran90 to add python functionality to my existing fortran90 code. 我正在考虑将python嵌入fortran90的选项,以便为我现有的fortran90代码添加python功能。 I know that it can be done the other way around by extending python with fortran90 using the f2py from numpy. 我知道可以通过使用来自numpy的f2py使用fortran90扩展python来反过来做到这一点。 But, i want to keep my super optimized main loop in fortran and add python to do some additional tasks / evaluate further developments before I can do it in fortran, and also to ease up code maintenance. 但是,我想在fortran中保留我的超级优化主循环并添加python来执行一些额外的任务/评估进一步的开发,然后才能在fortran中完成它,并且还可以简化代码维护。 I am looking for answers for the following questions: 我正在寻找以下问题的答案:

1) Is there a library that already exists from which I can embed python into fortran? 1)是否存在已经存在的库,我可以将python嵌入到fortran中? (I am aware of f2py and it does it the other way around) 2) How do we take care of data transfer from fortran to python and back? (我知道f2py并且它反过来了)2)我们如何处理从fortran到python并返回的数据传输? 3) How can we have a call back functionality implemented? 3)我们如何实现回调功能? (Let me describe the scenario a bit....I have my main_fortran program in Fortran, that call Func1_Python module in python. Now, from this Func1_Python, I want to call another function...say Func2_Fortran in fortran) 4) What would be the impact of embedding the interpreter of python inside fortran in terms of performance....like loading time, running time, sending data (a large array in double precision) across etc. (让我稍微描述一下场景....我在Fortran中有我的main_fortran程序,在python中调用Func1_Python模块。现在,从这个Func1_Python,我想调用另一个函数...在Fortran中说Func2_Fortran)4)什么在性能方面将python的解释器嵌入到fortran中的影响......就像加载时间,运行时间,发送数据(双精度的大数组)等。

Thanks a lot in advance for your help!! 非常感谢您的帮助!

Edit1: I want to set the direction of the discussion right by adding some more information about the work I am doing. Edit1:我想通过添加一些关于我正在做的工作的更多信息来设置正确的讨论方向。 I am into scientific computing stuff. 我是科学计算的东西。 So, I would be working a lot on huge arrays / matrices in double precision and doing floating point operations. 因此,我会在双精度和浮点运算中对大型数组/矩阵进行大量工作。 So, there are very few options other than fortran really to do the work for me. 因此,除了fortran之外,很少有其他选择可以为我做这项工作。 The reason i want to include python into my code is that I can use NumPy for doing some basic computations if necessary and extend the capabilities of the code with minimal effort. 我想将python包含到我的代码中的原因是我可以使用NumPy在必要时进行一些基本计算,并以最小的努力扩展代码的功能。 For example, I can use several libraries available to link between python and some other package (say OpenFoam using PyFoam library). 例如,我可以使用几个库来链接python和其他一些包(比如使用PyFoam库的OpenFoam)。

1. Don't do it 1.不要这样做

I know that you're wanting to add Python code inside a Fortan program, instead of having a Python program with Fortran extensions. 我知道你想在Fortan程序中添加Python代码,而不是使用带有Fortran扩展的Python程序。 My first piece of advice is to not do this. 我的第一条建议是不要这样做。 Fortran is faster than Python at array arithmetic, but Python is easier to write than Fortran, it's easier to extend Python code with OOP techniques, and Python may have access to libraries that are important to you. Fortran在数组运算方面比Python更快,但Python比Fortran更容易编写,使用OOP技术扩展Python代码更容易,Python可以访问对您很重要的库。 You mention having a super-optimized main loop in Fortran; 你提到在Fortran中有一个超级优化的主循环; Fortran is great for super-optimized inner loops. Fortran非常适合超级优化的内环 The logic for passing a Fortran array around in a Python program with Numpy is much more straightforward than what you would have to do to correctly handle a Python object in Fortran. 使用Numpy在Python程序中传递Fortran数组的逻辑比在Fortran中正确处理Python对象所要做的要简单得多。

When I start a scientific computing project from scratch, I always write first in Python, identify performance bottlenecks, and translate those into Fortran. 当我从头开始一个科学计算项目时,我总是首先用Python编写,识别性能瓶颈,然后将它们转换为Fortran。 Being able to test faster Fortran code against validated Python code makes it easier to show that the code is working correctly. 能够针对经过验证的Python代码测试更快的Fortran代码,可以更轻松地显示代码是否正常工作。

Since you have existing code, extending the Python code with a module made in Fortran will require refactoring, but this process should be straightforward. 由于您有现有代码,因此使用Fortran中创建的模块扩展Python代码将需要重构,但此过程应该很简单。 Separate the initialization code from the main loop, break the loop into logical pieces, wrap each of these routines in a Python function, and then your main Python code can call the Fortran subroutines and interleave these with Python functions as appropriate. 将初始化代码与主循环分开,将循环分解为逻辑片段,将每个例程包装在Python函数中,然后您的主Python代码可以调用Fortran子例程并根据需要将它们与Python函数交错。 In this process, you may be able to preserve a lot of the optimizations you have in your main loop in Fortran. 在此过程中,您可以在Fortran的主循环中保留大量优化。 F2PY is a reasonably standard tool for this, so it won't be tough to find people who can help you with whatever problems will arise. F2PY是一个相当标准的工具,因此找到可以帮助您解决任何问题的人并不难。

2. System calls 2.系统调用

If you absolutely must have Fortran code calling Python code, instead of the other way around, the simplest way to do this is to just have the Fortran code write some data to disk, and run the Python code with a SYSTEM or EXECUTE_COMMAND_LINE . 如果绝对必须让Fortran代码调用Python代码,而不是相反,最简单的方法是让Fortran代码将一些数据写入磁盘,并使用SYSTEMEXECUTE_COMMAND_LINE运行Python代码。 If you use EXECUTE_COMMAND_LINE , you can have the Python code output its result to stdout, and the Fortran code can read it as character data; 如果使用EXECUTE_COMMAND_LINE ,则可以让Python代码将其结果输出到stdout,Fortran代码可以将其作为字符数据读取; if you have a lot of output (eg, a big matrix), it would make more sense for the Python code to output a file that the Fortran code then reads. 如果你有很多输出(例如,一个大矩阵),那么Python代码输出Fortran代码然后读取的文件会更有意义。 Disk read/write overhead could wind up being prohibitively significant for this. 磁盘读/写开销可能会对此非常重要。 Also, you would have to write Fortran code to output your data, Python code to read it, Python code to output it again, and Fortran code to re-input the data. 此外,您必须编写Fortran代码来输出数据,使用Python代码来读取它,使用Python代码再输出它,然后使用Fortran代码重新输入数据。 This code should be straightforward to write and test, but keeping these four parts in sync as you edit the code may turn into a headache. 这段代码应该直接编写和测试,但在编辑代码时保持这四个部分同步可能会变得令人头疼。

(This approach is tried in this Stack Overflow question ) (在此Stack Overflow问题中尝试了此方法)

3. Embedding Python in C in Fortran 3.在Fortran中用C嵌入Python

There is no way that I know of to directly pass a Python object in memory to Fortran. 我不知道直接将内存中的Python对象传递给Fortran。 However, Fortran code can call C code, and C code can have Python embedded in it. 但是,Fortran代码可以调用C代码,而C代码可以嵌入Python代码。 (See the Python tutorial on extending and embedding .) In general, extending Python (like I recommend in point 1) is preferable to embedding it in C/C++. (请参阅有关扩展和嵌入Python教程 。)通常,扩展Python(我在第1点推荐)比将其嵌入C / C ++更可取。 (See Extending Vs. Embedding: There is Only One Correct Decision .) Getting this to work will be a nightmare, because any communication problems between Python and Fortran could happen between Python and C, or between C and Fortran. (请参阅扩展与嵌入:只有一个正确的决定 。)实现这一点将是一场噩梦,因为Python和Fortran之间的任何通信问题都可能发生在Python和C之间,或者发生在C和Fortran之间。 I don't know if anyone is actually embedding Python in C in Fortran, and so getting help will be difficult. 我不知道是否有人在Fortran中实际嵌入Python,因此获得帮助将很困难。

If you are going to embed Python in Fortran, you will have to do it via Fortran's C interface; 如果你要在Fortran中嵌入Python,你必须通过Fortran的C接口来实现; that's what ISO_C_BINDING is for. 这就是ISO_C_BINDING的用途。 I would caution against embedding Python, not because of the technical difficulty in doing so, but because Python (the language or the community) seems adamantly opposed to Python being used as a subordinate language. 我会警告不要嵌入Python,不是因为这样做有技术上的困难,而是因为Python(语言或社区)似乎坚决反对将Python用作从属语言。 The common view is that whatever non-Python language your code is currently written in should be broken up into libraries and used to extend Python, never the other way around. 常见的观点是,您的代码当前编写的非Python语言应该被分解为库并用于扩展Python,而不是相反。 So you will see (as here) more responses trying to convince you that you really don't want to do what you actually want to do than actual technical assistance. 所以你会看到(如此处)更多回复试图说服你,你真的不想做你真正想做的事情而不是实际的技术援助。

This is not flaming or editorializing or making a moral judgment; 这不是燃烧或编辑或做出道德判断; this is a simple statement of fact. 这是一个简单的事实陈述。 You will not get help from the Python community if you try to embed Python. 如果您尝试嵌入Python,则无法从Python社区获得帮助。

If what you need is functionality beyond what the Fortran language itself supports (eg filesystem operations) and you do not specifically need Python and you want a language more expressive than C, you may want to look at embedding Lua instead. 如果您需要的功能超出了Fortran语言本身所支持的功能(例如文件系统操作), 并且您并不特别需要Python, 并且您希望语言比C语言更具表现力,那么您可能需要考虑嵌入Lua。 Unlike Python, Lua is specifically meant to be embedded so you are likely to face much less social and technical resistance. 与Python不同,Lua专门用于嵌入,因此您可能面临更少的社交和技术阻力。

There are a number of projects which integrate Fortran and Lua , the most complete one I've seen to date is Aotus . 有许多项目整合了Fortran和Lua ,我见过的最完整的项目是Aotus The author is very responsive and the integration process is simple. 作者非常敏感,整合过程很简单。

Admittedly, this does not answer the original question (how to embed a Python interpreter in a Fortran 90 application) but to be fair, none of the other responses do either. 不可否认,这并没有回答原始问题(如何在Fortran 90应用程序中嵌入Python解释器),但公平地说,其他任何响应都没有。 I use Python as my portable general-purpose language of choice these days and I'd really prefer to stick with it when extending our primary products (written in Fortran). 我最近使用Python作为我的便携式通用语言,在扩展我们的主要产品(用Fortran编写)时,我更愿意坚持使用它。 For the reasons laid out above, I abandoned my attempts to embed Python and switched to embedding Lua; 由于上面提到的原因,我放弃了嵌入Python并尝试嵌入Lua的尝试; for social reasons, I feel Lua is a much better technical choice. 出于社会原因,我觉得Lua是一个更好的技术选择。 It's not my first choice but it's workable, at least in my case. 这不是我的第一选择,但它是可行的,至少在我的情况下。

Apologies if I've offended anyone; 如果我冒犯了任何人,我会道歉; I'm not trying to pick a fight, just relating my experience when researching this specific topic. 我不打算挑选一场战斗,只是在研究这个特定主题时提到我的经验。

I have developed the library Forpy that allows you to use Python in Fortran (embedding). 我开发了一个库Forpy ,它允许你在Fortran中使用Python(嵌入)。 It uses Fortran C interoperability to call Python C API functions. 它使用Fortran C互操作性来调用Python C API函数。

While I agree that extending (using Fortran in Python) is often preferable, embedding has its uses: 虽然我同意扩展(在Python中使用Fortran)通常更可取,但嵌入有其用途:

  • Large, existing Fortran codes might need a substantial amount of refactoring before they can be used from Python - here embedding can save development time 大型现有的Fortran代码可能需要大量的重构才能从Python中使用 - 这里嵌入可以节省开发时间
  • Replacing a part of an existing code with a Python implementation 用Python实现替换现有代码的一部分
  • Temporarily embedding Python to experiment with a given Fortran code: for example to test alternative algorithms or to extract intermediary results 暂时嵌入Python以试验给定的Fortran代码:例如,测试替代算法或提取中间结果

Besides embedding, Forpy also supports extending Python. 除了嵌入, Forpy还支持扩展Python。 With Forpy you can write a Python extension module entirely in Fortran. 使用Forpy您可以完全在Fortran中编写Python扩展模块。 An advantage to existing tools such as f2py is that you can use Python datatypes (eg to write a function that takes a Python list as argument or a function that returns a Python dict). 现有工具(如f2py )的一个优点是可以使用Python数据类型(例如,编写一个以Python列表作为参数的函数或一个返回Python dict的函数)。

Working with existing, possibly legacy, Fortran codes is often very challenging and I think that developers should have tools at their disposal both for embedding and extending Python. 使用现有的,可能是遗留的Fortran代码通常非常具有挑战性,我认为开发人员应该拥有可用于嵌入和扩展Python的工具。

I have tried out several approaches to solve the problem and I have found one possibly optimal way of doing it. 我已经尝试了几种解决问题的方法,我发现了一种可能的最佳方法。 I will briefly list down the approaches and the results. 我将简要列出方法和结果。

1) Embedding via System call: Everytime we want to access python from fortran, we use the system call to execute some python script and exchange data between them. 1)通过系统调用嵌入:每次我们想从fortran访问python时,我们使用系统调用来执行一些python脚本并在它们之间交换数据。 The speed in this approach is limited by the disk read, write (in this age of cache level optimization of code, going to disk is a mortal sin). 这种方法的速度受到磁盘读取,写入的限制(在这个代码的缓存级别优化时代,进入磁盘是致命的罪恶)。 Also, we need to initialize the interpreter everytime we want to execute the script, which is a considerable overhead. 此外,我们需要在每次执行脚本时初始化解释器,这是一个相当大的开销。 A simple Runge Kutta 4th order method running for 300 timesteps took a whopping 59 seconds to execute. 一个简单的Runge Kutta四阶方法运行300次步骤需要花费59秒才能执行。

2) Going from Fortran to Python via C: We use the ISO_C bindings to communicate between Fortran and C; 2)通过C从Fortran转到Python:我们使用ISO_C绑定在Fortran和C之间进行通信; and we embed the Python interpreter inside C. I got parts of it working, but in the meanwhile I found a better way and dropped this idea. 我们在C里面嵌入了Python解释器。我有部分工作,但同时我找到了一个更好的方法并放弃了这个想法。 I would still like to evaluate this for the sake of completeness though. 我仍然想为了完整性而评估这个。

3) Using f2py to import Fortran subroutines to Python (Extending) : Here, we take the main loop out of Fortran and code it in Python (this approach is called Extending Python with Fortran); 3)使用f2py将Fo​​rtran子程序导入Python(扩展):在这里,我们将主循环从Fortran中取出并在Python中编码(这种方法称为使用Fortran扩展Python); and we import all Fortran subroutines into Python using f2py ( http://cens.ioc.ee/projects/f2py2e/usersguide/ ). 然后我们使用f2py将所有Fortran子程序导入Python( http://cens.ioc.ee/projects/f2py2e/usersguide/ )。 We have the flexibility of having the most important data in any Scientific application, ie the outermost loop (generally the time loop) in Python so that we can couple it with other applications. 我们可以灵活地在任何Scientific应用程序中拥有最重要的数据,即Python中最外层的循环(通常是时间循环),以便我们可以将它与其他应用程序耦合。 But, we also have the drawback of having to exchange possibly more than needed data between Fortran and Python. 但是,我们还有一个缺点,即必须在Fortran和Python之间交换可能需要的数据。 The same Runge Kutta 4th order method example took 0.372 seconds to execute. 同样的Runge Kutta四阶方法示例需要0.372秒才能执行。

4) Mimicking Embedding via Extending: Till now we have seen the two pure approaches of Embedding (the main loop stays in fortran and we call python as needed) and Extending (the main loop stay in python and we call fortran as needed). 4)通过扩展模仿嵌入:到现在为止我们已经看到了两种纯粹的嵌入方法(主循环停留在fortran中,我们根据需要调用python)和Extending(主循环保留在python中,我们根据需要调用fortran)。 There is another way of doing it, which I found to be the most optimal. 还有另一种方法,我发现这是最优化的。 Transferring parts of main loop into Python would lead to an overhead, which may not be necessary all the time. 将主循环的部分转移到Python中会导致开销,这可能不是必须的。 To get rid of this overhead, we can keep the main loop in Fortran which is converted into a subroutine without any changes, have a pseudo main loop in Python, which just calls the main loop in Fortran and the Program executes as if it was our untouched Fortran program. 为了摆脱这种开销,我们可以将主循环保留在Fortran中,并将其转换为子程序而不进行任何更改,在Python中有一个伪主循环,它只调用Fortran中的主循环并且程序执行就好像它是我们的未受影响的Fortran计划。 Whenever necessary, we can use a callback function to come back to python with the required data, execute a script and go back to fortran again. 必要时,我们可以使用回调函数返回带有所需数据的python,执行脚本并再次返回fortran。 In this approach, the Runge Kutta 4th Order method took 0.083 seconds. 在这种方法中,Runge Kutta 4th Order方法耗时0.083秒。 I profiled the code, and found that the initialization of python interpreter and loading took 0.075 seconds and the program took only 0.008 seconds (which includes 300 callback functions to python). 我分析了代码,发现python解释器和加载的初始化花了0.075秒,程序只花了0.008秒(其中包括300个回调函数到python)。 The original fortran code took 0.007 seconds. 原始的fortran代码耗时0.007秒。 So, we get almost Fortran like performance with python like flexibility using this approach. 因此,使用这种方法,我们几乎可以像使用python那样灵活地运行Fortran。

There is a very easy way to do this using f2py . 使用f2py有一种非常简单的方法。 Write your python method and add it as an input to your Fortran subroutine. 编写python方法并将其添加为Fortran子例程的输入。 Declare it in both the cf2py hook and the type declaration as EXTERNAL and also as its return value type, eg REAL*8 . cf2py钩子和类型声明中将其声明为EXTERNAL ,并将其作为返回值类型,例如REAL*8 Your Fortran code will then have a pointer to the address where the python method is stored. 然后,您的Fortran代码将指向存储python方法的地址。 It will be SLOW AS MOLASSES, but for testing out algorithms it can be useful. 它将是SLOW AS MOLASSES,但是对于测试算法它可能是有用的。 I do this often (I port a lot of ancient spaghetti Fortran to python modules...) It's also a great way to use things like optimised Scipy calls in legacy fortran 我经常这样做(我将很多古老的意​​大利面条Fortran移植到python模块......)这也是在遗产fortran中使用像优化的Scipy调用这样的东西的好方法

I've just successfully embedded Python into our in-house ~500 KLOC Fortran program with cffi . 我刚刚用cffi成功地将Python嵌入到我们内部的~500 KLOC Fortran程序中。 An important aspect was not to touch the existing code. 一个重要方面是不触及现有代码。 The program is written in Fortran 95. I wrote a thin 2003 wrapper using the iso_c_binding module that simply imports data from the various modules, gets C pointers to those data and/or wraps Fortran types into C structs, puts everything into a single type/struct and sends off to a C function. 该程序是用Fortran 95编写的。我使用iso_c_binding模块编写了一个瘦的2003包装器,它只是从各个模块导入数据,获取指向这些数据的C指针和/或将Fortran类型包装成C结构,将所有内容放入单个类型/ struct并发送给C函数。 This C function happens to be a Python function wrapped with cffi . 这个C函数碰巧是用cffi包装的Python函数。 It unpacks the C struct into a more user-friendly Python object, wraps Fortran arrays as Numpy arrays (no copying) and then either drops into an interactive Python console or runs a Python script, based on user configuration. 它将C结构解压缩为更加用户友好的Python对象,将Fortran数组包装为Numpy数组(无需复制),然后根据用户配置放入交互式Python控制台或运行Python脚本。 There is no need to write C code except for a single header file. 除单个头文件外,无需编写C代码。 There is obviously quite some overhead, but this functionality is intended for extendibility, not performance. 显然有一些开销,但此功能旨在实现可扩展性,而非性能。

I would advise against f2py. 我会建议反对f2py。 It's not maintained well and severely limits the public interface of your Fortran code. 它维护得不好,严重限制了Fortran代码的公共接口。

I wrote a library for that, forcallpy , using a C layer which embeds Python expressions interpretation functions, and working specifically on arguments passing between Fortran and Python to make scripts call as easy as possible (uses embedded numpy to directly map Fortran arrays inside ndarrays, use arguments names to know their type in the C/Python side). 我为此编写了一个库, forcallpy ,使用嵌入Python表达式解释函数的C层,并专门处理在Fortran和Python之间传递的参数,使脚本调用尽可能简单(使用嵌入式numpy直接映射ndarrays中的Fortran数组,使用参数名称来了解它们在C / Python方面的类型)。

You can see some examples in the documentation at readthedocs. 您可以在readthedocs的文档中看到一些示例。

Laurent. 洛朗。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM