簡體   English   中英

將python嵌入到fortran 90中

[英]Embed python into fortran 90

我正在考慮將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)。

1.不要這樣做

我知道你想在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是一個相當標准的工具,因此找到可以幫助您解決任何問題的人並不難。

2.系統調用

如果絕對必須讓Fortran代碼調用Python代碼,而不是相反,最簡單的方法是讓Fortran代碼將一些數據寫入磁盤,並使用SYSTEMEXECUTE_COMMAND_LINE運行Python代碼。 如果使用EXECUTE_COMMAND_LINE ,則可以讓Python代碼將其結果輸出到stdout,Fortran代碼可以將其作為字符數據讀取; 如果你有很多輸出(例如,一個大矩陣),那么Python代碼輸出Fortran代碼然后讀取的文件會更有意義。 磁盤讀/寫開銷可能會對此非常重要。 此外,您必須編寫Fortran代碼來輸出數據,使用Python代碼來讀取它,使用Python代碼再輸出它,然后使用Fortran代碼重新輸入數據。 這段代碼應該直接編寫和測試,但在編輯代碼時保持這四個部分同步可能會變得令人頭疼。

(在此Stack Overflow問題中嘗試了此方法)

3.在Fortran中用C嵌入Python

我不知道直接將內存中的Python對象傳遞給Fortran。 但是,Fortran代碼可以調用C代碼,而C代碼可以嵌入Python代碼。 (請參閱有關擴展和嵌入Python教程 。)通常,擴展Python(我在第1點推薦)比將其嵌入C / C ++更可取。 (請參閱擴展與嵌入:只有一個正確的決定 。)實現這一點將是一場噩夢,因為Python和Fortran之間的任何通信問題都可能發生在Python和C之間,或者發生在C和Fortran之間。 我不知道是否有人在Fortran中實際嵌入Python,因此獲得幫助將很困難。

如果你要在Fortran中嵌入Python,你必須通過Fortran的C接口來實現; 這就是ISO_C_BINDING的用途。 我會警告不要嵌入Python,不是因為這樣做有技術上的困難,而是因為Python(語言或社區)似乎堅決反對將Python用作從屬語言。 常見的觀點是,您的代碼當前編寫的非Python語言應該被分解為庫並用於擴展Python,而不是相反。 所以你會看到(如此處)更多回復試圖說服你,你真的不想做你真正想做的事情而不是實際的技術援助。

這不是燃燒或編輯或做出道德判斷; 這是一個簡單的事實陳述。 如果您嘗試嵌入Python,則無法從Python社區獲得幫助。

如果您需要的功能超出了Fortran語言本身所支持的功能(例如文件系統操作), 並且您並不特別需要Python, 並且您希望語言比C語言更具表現力,那么您可能需要考慮嵌入Lua。 與Python不同,Lua專門用於嵌入,因此您可能面臨更少的社交和技術阻力。

有許多項目整合了Fortran和Lua ,我見過的最完整的項目是Aotus 作者非常敏感,整合過程很簡單。

不可否認,這並沒有回答原始問題(如何在Fortran 90應用程序中嵌入Python解釋器),但公平地說,其他任何響應都沒有。 我最近使用Python作為我的便攜式通用語言,在擴展我們的主要產品(用Fortran編寫)時,我更願意堅持使用它。 由於上面提到的原因,我放棄了嵌入Python並嘗試嵌入Lua的嘗試; 出於社會原因,我覺得Lua是一個更好的技術選擇。 這不是我的第一選擇,但它是可行的,至少在我的情況下。

如果我冒犯了任何人,我會道歉; 我不打算挑選一場戰斗,只是在研究這個特定主題時提到我的經驗。

我開發了一個庫Forpy ,它允許你在Fortran中使用Python(嵌入)。 它使用Fortran C互操作性來調用Python C API函數。

雖然我同意擴展(在Python中使用Fortran)通常更可取,但嵌入有其用途:

  • 大型現有的Fortran代碼可能需要大量的重構才能從Python中使用 - 這里嵌入可以節省開發時間
  • 用Python實現替換現有代碼的一部分
  • 暫時嵌入Python以試驗給定的Fortran代碼:例如,測試替代算法或提取中間結果

除了嵌入, Forpy還支持擴展Python。 使用Forpy您可以完全在Fortran中編寫Python擴展模塊。 現有工具(如f2py )的一個優點是可以使用Python數據類型(例如,編寫一個以Python列表作為參數的函數或一個返回Python dict的函數)。

使用現有的,可能是遺留的Fortran代碼通常非常具有挑戰性,我認為開發人員應該擁有可用於嵌入和擴展Python的工具。

我已經嘗試了幾種解決問題的方法,我發現了一種可能的最佳方法。 我將簡要列出方法和結果。

1)通過系統調用嵌入:每次我們想從fortran訪問python時,我們使用系統調用來執行一些python腳本並在它們之間交換數據。 這種方法的速度受到磁盤讀取,寫入的限制(在這個代碼的緩存級別優化時代,進入磁盤是致命的罪惡)。 此外,我們需要在每次執行腳本時初始化解釋器,這是一個相當大的開銷。 一個簡單的Runge Kutta四階方法運行300次步驟需要花費59秒才能執行。

2)通過C從Fortran轉到Python:我們使用ISO_C綁定在Fortran和C之間進行通信; 我們在C里面嵌入了Python解釋器。我有部分工作,但同時我找到了一個更好的方法並放棄了這個想法。 我仍然想為了完整性而評估這個。

3)使用f2py將Fo​​rtran子程序導入Python(擴展):在這里,我們將主循環從Fortran中取出並在Python中編碼(這種方法稱為使用Fortran擴展Python); 然后我們使用f2py將所有Fortran子程序導入Python( http://cens.ioc.ee/projects/f2py2e/usersguide/ )。 我們可以靈活地在任何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。

使用f2py有一種非常簡單的方法。 編寫python方法並將其添加為Fortran子例程的輸入。 cf2py鈎子和類型聲明中將其聲明為EXTERNAL ,並將其作為返回值類型,例如REAL*8 然后,您的Fortran代碼將指向存儲python方法的地址。 它將是SLOW AS MOLASSES,但是對於測試算法它可能是有用的。 我經常這樣做(我將很多古老的意​​大利面條Fortran移植到python模塊......)這也是在遺產fortran中使用像優化的Scipy調用這樣的東西的好方法

我剛剛用cffi成功地將Python嵌入到我們內部的~500 KLOC Fortran程序中。 一個重要方面是不觸及現有代碼。 該程序是用Fortran 95編寫的。我使用iso_c_binding模塊編寫了一個瘦的2003包裝器,它只是從各個模塊導入數據,獲取指向這些數據的C指針和/或將Fortran類型包裝成C結構,將所有內容放入單個類型/ struct並發送給C函數。 這個C函數碰巧是用cffi包裝的Python函數。 它將C結構解壓縮為更加用戶友好的Python對象,將Fortran數組包裝為Numpy數組(無需復制),然后根據用戶配置放入交互式Python控制台或運行Python腳本。 除單個頭文件外,無需編寫C代碼。 顯然有一些開銷,但此功能旨在實現可擴展性,而非性能。

我會建議反對f2py。 它維護得不好,嚴重限制了Fortran代碼的公共接口。

我為此編寫了一個庫, forcallpy ,使用嵌入Python表達式解釋函數的C層,並專門處理在Fortran和Python之間傳遞的參數,使腳本調用盡可能簡單(使用嵌入式numpy直接映射ndarrays中的Fortran數組,使用參數名稱來了解它們在C / Python方面的類型)。

您可以在readthedocs的文檔中看到一些示例。

洛朗。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM