F2Py आवंटन योग्य और ग्रहण आकृति के साथ


18

मैं f2pyआधुनिक फोरट्रान के साथ उपयोग करना चाहूंगा । विशेष रूप से मैं काम करने के लिए निम्नलिखित मूल उदाहरण प्राप्त करने की कोशिश कर रहा हूं। यह सबसे छोटा उपयोगी उदाहरण है जिसे मैं उत्पन्न कर सकता हूं।

! alloc_test.f90
subroutine f(x, z)
  implicit none

! Argument Declarations !
  real*8, intent(in) ::  x(:)
  real*8, intent(out) :: z(:)

! Variable Declarations !
  real*8, allocatable :: y(:)
  integer :: n

! Variable Initializations !
  n = size(x)
  allocate(y(n))

! Statements !
  y(:) = 1.0
  z = x + y

  deallocate(y)
  return
end subroutine f

ध्यान दें कि nइनपुट पैरामीटर के आकार से अनुमान लगाया गया है x। ध्यान दें कि yसबरूटीन के शरीर के भीतर आवंटित और सौदा किया जाता है।

जब मैं इसके साथ संकलन करता हूं f2py

f2py -c alloc_test.f90 -m alloc

और फिर पायथन में चला

from alloc import f
from numpy import ones
x = ones(5)
print f(x)

मुझे निम्नलिखित त्रुटि मिलती है

ValueError: failed to create intent(cache|hide)|optional array-- must have defined dimensions but got (-1,)

इसलिए मैं जाता हूं और pyfमैन्युअल रूप से फ़ाइल बनाता हूं और संपादित करता हूं

f2py -h alloc_test.pyf -m alloc alloc_test.f90

मूल

python module alloc ! in 
    interface  ! in :alloc
        subroutine f(x,z) ! in :alloc:alloc_test.f90
            real*8 dimension(:),intent(in) :: x
            real*8 dimension(:),intent(out) :: z
        end subroutine f
    end interface 
end python module alloc

संशोधित

python module alloc ! in 
    interface  ! in :alloc
        subroutine f(x,z,n) ! in :alloc:alloc_test.f90
            integer, intent(in) :: n
            real*8 dimension(n),intent(in) :: x
            real*8 dimension(n),intent(out) :: z
        end subroutine f
    end interface 
end python module alloc

अब यह चलता है लेकिन आउटपुट का मान zहमेशा होता है 0। कुछ डिबग प्रिंटिंग से पता चलता है कि सबरूटीन के भीतर nमूल्य है । मुझे लगता है कि मुझे इस स्थिति को ठीक से प्रबंधित करने के लिए कुछ हेडर जादू याद आ रहे हैं । 0ff2py

अधिक आम तौर पर पायथन में उपरोक्त सबरूटीन को जोड़ने का सबसे अच्छा तरीका क्या है? मैं दृढ़ता से पसंद करूँगा कि सबरूटीन को स्वयं संशोधित न करें।


मैट, क्या आप ओन्ड्रेज सर्टिफिक के सर्वोत्तम अभ्यास गाइड से परिचित हैं, विशेष रूप से, पायथन सेक्शन के साथ इंटरसेपिंग ? हम PyClaw के लिए एक समान इंटरफेसिंग मुद्दे पर चर्चा कर रहे हैं और इसे अभी तक इस बिंदु पर हल नहीं किया है :)
एरन अहमदिया

जवाबों:


23

मैं f2py इंटर्नल से सुपर परिचित नहीं हूं, लेकिन मैं फोरट्रान को लपेटने से बहुत परिचित हूं। F2py नीचे कुछ या सभी चीजों को स्वचालित करता है।

  1. आपको पहले iso_c_binding मॉड्यूल का उपयोग करके C को निर्यात करने की आवश्यकता है, जैसा कि यहां उदाहरण के लिए वर्णित है:

    http://fortran90.org/src/best-practices.html#interfacing-with-c

    अस्वीकरण: मैं Fortran90.org पृष्ठों का मुख्य लेखक हूं। सी। से फोर्ट्रान को कॉल करने का यह एकमात्र प्लेटफ़ॉर्म और कंपाइलर स्वतंत्र तरीका है। यह F2003 है, इसलिए इन दिनों किसी अन्य तरीके का उपयोग करने का कोई कारण नहीं है।

  2. आप पूर्ण लंबाई निर्दिष्ट (स्पष्ट आकार) के साथ केवल सरणियों को निर्यात / कॉल कर सकते हैं, जो है:

    integer(c_int), intent(in) :: N
    real(c_double), intent(out) :: mesh(N)
    

    लेकिन आकार ग्रहण नहीं:

    real(c_double), intent(out) :: mesh(:)

    ऐसा इसलिए है क्योंकि C भाषा स्वयं ऐसे सरणियों का समर्थन नहीं करती है। F2008 या बाद में (मुझे यकीन नहीं है) में इस तरह के समर्थन को शामिल करने के लिए चर्चा है, और जिस तरह से यह काम करेगा वह कुछ सहायक सी डेटा संरचनाओं के माध्यम से है, जैसा कि आपको सरणी के बारे में आकार की जानकारी ले जाने की आवश्यकता है।

    फोरट्रान में, आपको मुख्य रूप से मान आकार का उपयोग करना चाहिए, केवल विशेष मामलों में आपको स्पष्ट आकार का उपयोग करना चाहिए, जैसा कि यहां वर्णित है:

    http://fortran90.org/src/best-practices.html#arrays

    इसका मतलब है, कि आपको अपने मान के आकार के उप-रेखा के चारों ओर एक साधारण आवरण लिखने की आवश्यकता है, जो कि ऊपर दिए गए मेरे पहले लिंक के अनुसार, स्पष्ट आकार सरणियों में चीजों को लपेट देगा।

  3. एक बार जब आपके पास एक सी हस्ताक्षर होता है, तो इसे पाइथन से किसी भी तरह से कॉल करें, जैसे आप चाहें, मैं साइथन का उपयोग करता हूं, लेकिन आप हाथ से सीटीपी, या सी / एपीआई का उपयोग कर सकते हैं।

  4. deallocate(y)बयान की जरूरत नहीं है, फोरट्रान स्वचालित रूप से deallocates।

    http://fortran90.org/src/best-practices.html#allocatable-arrays

  5. real*8उपयोग नहीं किया जाना चाहिए, बल्कि real(dp):

    http://fortran90.org/src/best-practices.html#floating-point-numbers

  6. बयान y(:) = 1.0एकल सटीकता में 1.0 असाइन कर रहा है, इसलिए बाकी अंक यादृच्छिक होंगे! यह एक आम नुकसान है:

    http://fortran90.org/src/gotchas.html#floating-point-numbers

    आपको उपयोग करने की आवश्यकता है y(:) = 1.0_dp

  7. लिखने के बजाय y(:) = 1.0_dp, आप बस लिख सकते हैं, बस y = 1। आप सटीकता खोए बिना एक फ्लोटिंग पॉइंट नंबर को पूर्णांक असाइन कर सकते हैं, और आपको अनावश्यक (:)को वहां डालने की आवश्यकता नहीं है । बहुत सरल।

  8. के बजाय

    y = 1
    z = x + y

    महज प्रयोग करें

    z = x + 1

    और yसरणी के साथ बिल्कुल परेशान नहीं है ।

  9. आपको सबरूटीन के अंत में "रिटर्न" स्टेटमेंट की आवश्यकता नहीं है।

  10. अंत में, आपको संभवतः मॉड्यूल का उपयोग करना चाहिए, और बस implicit noneमॉड्यूल स्तर पर रखना चाहिए और आपको इसे प्रत्येक सबरूटीन में दोहराने की आवश्यकता नहीं है।

    अन्यथा यह मुझे अच्छा लगता है। यहाँ ऊपर दिए गए सुझावों का अनुसरण करते हुए कोड है ::

    module test
    use iso_c_binding, only: c_double, c_int
    implicit none
    integer, parameter :: dp=kind(0.d0)
    
    contains
    
    subroutine f(x, z)
    real(dp), intent(in) ::  x(:)
    real(dp), intent(out) :: z(:)
    z = x + 1
    end subroutine
    
    subroutine c_f(n, x, z) bind(c)
    integer(c_int), intent(in) :: n
    real(c_double), intent(in) ::  x(n)
    real(c_double), intent(out) :: z(n)
    call f(x, z)
    end subroutine
    
    end module

    यह सरलीकृत सबरूटीन के साथ-साथ सी आवरण भी दिखाता है।

    जहाँ तक f2py के रूप में, यह संभवतः आपके लिए इस आवरण को लिखने की कोशिश करता है और विफल रहता है। मुझे यह भी निश्चित नहीं है कि यह iso_c_bindingमॉड्यूल का उपयोग कर रहा है या नहीं । इसलिए इन सभी कारणों से, मैं चीजों को हाथ से लपेटना पसंद करता हूं। फिर यह बिल्कुल स्पष्ट है कि क्या हो रहा है।


जहां तक ​​मुझे पता है, f2py आईएसओ सी बाइंडिंग पर निर्भर नहीं करता है (इसका प्राथमिक लक्ष्य फोरट्रान 77 और फोरट्रान 90 कोड है)।
एरन अहमदिया

मुझे पता था कि मैं थोड़ा गूंगा था, yलेकिन मैं चाहता था कि कुछ आवंटित किया जाए (मेरा वास्तविक कोड गैर-तुच्छ आवंटन है)। मैं हालांकि कई अन्य बिंदुओं के बारे में नहीं जानता था। ऐसा लगता है कि मुझे कुछ प्रकार के फोरट्रान 90 सर्वोत्तम प्रथाओं गाइड में जाना चाहिए .... पूरी तरह से उत्तर के लिए धन्यवाद!
21

ध्यान दें कि आज के फोरट्रान संकलक का उपयोग करके, आप F77 को ठीक उसी तरह से लपेटते हैं --- एक साधारण iso_c_binding रैपर लिखकर और उस से लीगेसी F77 सबरूटीन को कॉल करें।
ओन्ड

6

आपको बस इतना करना है:

!alloc_test.f90
subroutine f(x, z, n)
  implicit none

! Argument Declarations !
  integer :: n
  real*8, intent(in) ::  x(n)
  real*8, intent(out) :: z(n)

! Variable Declarations !
  real*8, allocatable :: y(:)

! Variable Initializations !
  allocate(y(n))

! Statements !
  y(:) = 1.0
  z = x + y

  deallocate(y)
  return
end subroutine f

हालाँकि सरणी x और z का आकार अब एक स्पष्ट तर्क के रूप में पारित हो गया है, f2py तर्क n को वैकल्पिक बनाता है। निम्नलिखित कार्य के डॉकस्ट्रिंग के रूप में यह अजगर को प्रतीत होता है:

Type:       fortran
String Form:<fortran object>
Docstring:
f - Function signature:
  z = f(x,[n])
Required arguments:
  x : input rank-1 array('d') with bounds (n)
Optional arguments:
  n := len(x) input int
Return objects:
  z : rank-1 array('d') with bounds (n)

अजगर से इसे आयात और कॉल करना:

from alloc import f
from numpy import ones
x = ones(5)
print f(x)

निम्नलिखित आउटपुट देता है:

[ 2.  2.  2.  2.  2.]

क्या आकार के रूप में कुछ गैर-तुच्छ अभिव्यक्ति का उपयोग करने का एक तरीका है? उदाहरण के लिए, मैं पास हूं nऔर आकार की एक सरणी प्राप्त करना चाहता हूं 2 ** n। अब तक मुझे भी 2 ** n को एक अलग तर्क के रूप में पारित करना है।
एलेलो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.