2016-01-03 5 views
5

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

subroutine create_hist(a, n, dr, bins, hist) 
    integer, intent(in) :: n 
    real(8), intent(in) :: a(n) 
    real(8), intent(in) :: dr 
    integer, intent(out), allocatable :: hist(:) 
    real(8), intent(out), allocatable :: bins(:) 

    n_b = n_bins(a, n, dr) ! a function calculating the number of bins 
    allocate(bins(n_b+1)) 
    allocate(hist(n_b)) 
    hist = 0 

    !... Create the histogram hist by putting elems of a into bins 
end subroutine 

यह संख्या a की एक सरणी दिया बिन आकार dr के आधार पर एक हिस्टोग्राम हो और बनाने के लिए एक सरल कार्यक्रम है। सबसे पहले, यह फ़ंक्शन n_bins का उपयोग करके डिब्बे की संख्या प्राप्त करता है और उसके अनुसार सरणी bins और hist के लिए स्थान आवंटित करता है। के रूप में यह एक प्राकृतिक प्रतीत हो रहा है,

/tmp/tmpY5badz/src.linux-x86_64-2.6/mat_ops-f2pywrappers2.f90:32.37: 
     call create_hist_gnu(a, n, dr, bins, hist) 
Error: Actual argument for 'bins' must be ALLOCATABLE at (1) 

मैं यह समझ के रूप में, f2py कार्यावधि में सरणियों के लिए जगह आवंटित करने को बर्दाश्त नहीं करता है (पता नहीं क्यों:

जबकि gfortran इस कोड को ठीक संकलित, f2py एक त्रुटि को जन्म देती है वैज्ञानिक जरूरत)।

क्या कोई भी रन-टाइम पर फोरट्रान सरणी आवंटित करने का तरीका सुझा सकता है ताकि f2py इससे खुश हो?

उत्तर

1

जहां तक ​​मुझे पता है कि f2py डमी तर्कों (कभी-कभी फ़ंक्शन पैरामीटर के रूप में जाना जाता है) का समर्थन नहीं करता है जिसमें विशेषता ALLOCATABLE है। एक विकल्प यह एक पर्याप्त पर्याप्त स्पष्ट आकार सरणी बनाने के लिए होगा। फिर आप सरणी के केवल एक निश्चित भाग का उपयोग करेंगे।

subroutine create_hist(a, n, dr, n_b_max, bins, hist) 
    integer, intent(in) :: n 
    real(8), intent(in) :: a(n) 
    real(8), intent(in) :: dr 
    integer, intent(in) :: n_b_max 
    integer, intent(out) :: hist(n_b_max) 
    real(8), intent(out) :: bins(n_b_max+1) 

वैसे, real(8) का उपयोग कर एक पोर्टेबल तरीका 64-बिट परिशुद्धता निर्दिष्ट करने का तरीका और कुछ compilers साथ विफल हो जाएगा नहीं है। यहां तक ​​कि पुराना पुराना double precision बेहतर है क्योंकि यह हमेशा कुछ और संकलित करने के लिए 64 बिट तक संकलित होगा।

+0

क्या पर्याप्त पर्याप्त आकार-आकार तर्क कार्य भी होगा? और वहां "लौटा आकार" तर्क भी होना चाहिए ताकि कॉलर जानता है कि सरणी कितनी मान्य है (उपयोग के मामले पर निर्भर करता है, मुझे यकीन है)? [किसी चीज से ज्यादा चीजों की अज्ञानता में पूछना।] – francescalus

+0

हां, मान लिया गया आकार भी काम करेगा। आप लौटे आकार के बारे में भी सही हैं। अन्यथा यह (वे एक नकारात्मक संख्या, या कुछ और करने के लिए प्रारंभ किया जा सकता है 'bins' के मूल्यों से अनुमान लगाया जा करने के लिए? आप इसे परीक्षण किया होगा। –

5

कुछ वैध विकल्प/कार्य-राउंड हैं जिनका आप उपयोग कर सकते हैं।

1. शायद सबसे सरल व्यवस्था करने के लिए अजगर समारोह n_bins फोन के लिए, और फिर (के एक थोड़ा संशोधित संस्करण) से परिणाम का उपयोग कॉल करने के लिए की गैर allocatable उत्पादन सरणियों के साथ create_hist समारोह होगा सही आकार

अजगर में

अर्थात:

n_b = n_bins(a,dr) # don't need to pass n - inferred from a 
bins,hist = create_hist(a,dr,n_b) # bins and hist are auto-allocated 
create_hist को फोरट्रान इंटरफेस के साथ

अब के रूप में

subroutine create_hist(a, n, dr, n_b, bins, hist) 
    integer, intent(in) :: n 
    real(8), intent(in) :: a(n) 
    real(8), intent(in) :: dr 
    integer, intent(in) :: n_b 
    integer, intent(out) :: hist(n_b) 
    real(8), intent(out) :: bins(n_b+1) 

    ! code follows 

! you also need to specify the function n_bins... 

यह केवल मामलों में जहां आप n_bins सस्ते में और बाहर create_hist से कॉल कर सकते हैं में काम करता है परिभाषित किया। मुझे उन मामलों के लिए आवंटित सरणी अनुकरण करने के लिए 2 विधियों के बारे में पता है, जहां यह लागू नहीं होता है (यानी सरणी आकारों को काम करने के लिए कोड महंगा है और आसानी से अलग नहीं किया जा सकता है)।

2. पहला मॉड्यूल स्तर आवंटनीय सरणी (दस्तावेज here में वर्णित) का उपयोग करना है। यह अनिवार्य रूप से एक आवंटित वैश्विक चर है - आप अपने फ़ंक्शन को कॉल करते हैं, यह डेटा को वैश्विक चर में सहेजता है और फिर आप इसे पायथन से एक्सेस करते हैं। नुकसान यह है कि यह थ्रेड-सुरक्षित नहीं है (यानी।यह बुरा है अगर आप समानांतर में एक साथ create_hist फोन)

module something 
    real(8), allocatable :: bins(:) 
    integer, allocatable :: hist(:) 
contains 
    subroutine create_hist(a,n,dr) 
     integer, intent(in) :: n 
     real(8), intent(in) :: a(n) 
     real(8), intent(in) :: dr 
     integer :: n_b 

     n_b = n_bins(a,n,dr) 

     allocate(bins(n_b+1)) 
     allocate(hist(n_b)) 
     ! code follows 
    end subroutine 
end module 

अजगर कॉल तो लग रहा है

something.create_hist(a,n,dr) 
bins = something.bins # or possible bins = copy.copy(something.bins) 
hist = something.hist # or possible hist = copy.copy(something.hist) 

3. अन्य तरीके से जो मैं काफी पसंद ही समारोह के भीतर सरणियों आवंटित करने के लिए है की तरह (यानी पैरामीटर के रूप में उन्हें बाहर/बाहर पास न करें)। हालांकि, आप जो करते हैं वह एक पायथन कॉलबैक फ़ंक्शन है जिसे अंत में बुलाया जाता है और सरणी बचाता है। यह थ्रेड-सुरक्षित है (मुझे विश्वास है)।

fortran कोड तो जैसे

subroutine create_hist(a,n,dr,callback) 
    integer, intent(in) :: n 
    real(8), intent(in) :: a(n) 
    real(8), intent(in) :: dr 
    external callable ! note: better to specify the type with an interface block (see http://www.fortran90.org/src/best-practices.html#callbacks) 
    integer :: n_b 
    real(8), allocatable :: bins(:) 
    integer, allocatable :: hist(:) 

    n_b = n_bins(a,n,dr) 

    allocate(bins(n_b+1)) 
    allocate(hist(n_b)) 
    ! code follows 
    call callable(bins,hist,n_b) 
end subroutine 

दिखता दुर्भाग्य से यह तो थोड़ा और अधिक शामिल है।

python module create_hist__user__routines 
    interface create_hist_user_interface 
     subroutine callable(bins,hist,n_b) ! in :f:my_fortran_file.f90:stuff:create_hist:unknown_interface 
      real(kind=8), dimension(n_b+1) :: bins 
      integer, dimension(n_b) :: hist 
      integer :: n_b 
     end subroutine callable 
    end interface create_hist_user_interface 
end python module create_hist__user__routines 
: - (के रूप में उपयुक्त नाम बदलने के इस fortran_module नामक एक पायथन मॉड्यूल का निर्माण करना है), और फिर कॉलबैक फ़ंक्शन के आयामों को स्पष्ट करने का यह प्रासंगिक लाइनों को संशोधित आप कमांड f2py -m fortran_module -h fortran_module.pyf my_fortran_file.f90 साथ एक हस्ताक्षर फ़ाइल बनाने की आवश्यकता

संकलन कि f2py -c fortran_module.pyf my_fortran_file.f90

हुआ और उसके अजगर आवरण के साथ (यदि आप एक आसान इंटरफ़ेस देने के लिए) है कि लग रहा है

तरह
def create_hist(a,dr): 
    class SaveArraysCallable(object): 
     def __call__(self,bins,hist): 
      self.bins = bins.copy() 
      self.hist = hist.copy() 

    f = SaveArrayCallable() 
    fortran_module.create_hist(a,dr,f) 
    return f.bins, f.hist 

सारांश

कई मामलों के लिए विकल्प 1 शायद सबसे अच्छा है। अन्यथा विकल्प 2 या विकल्प 3. मैं विकल्प 3 पसंद करता हूं क्योंकि इससे बचने के लिए मल्टीथ्रेडिंग समस्याएं नहीं हैं (लेकिन वास्तव में यह एक कोने-केस है जिसे आप कभी नहीं देख पाएंगे)। विकल्प 2 को कार्यान्वित करना आसान है।

+0

वहाँ विकल्प 3 के लिए किसी भी प्रलेखन है?' Allocatable, आयाम (n_b + 1) 'फोरट्रान नियमों के विरुद्ध स्पष्ट रूप से है, लेकिन शायद f2py अपनी कॉलबैक इंटरफेस के लिए यह अनुमति देता है। हालांकि,' 'callable' create_hist' अंदर अभी भी अंतर्निहित इंटरफ़ेस है। –

+0

मैं विकल्प 3 का परीक्षण किया है और यह काम करता है। यह मेरी अपनी आविष्कार की एक खराब हैक है । इसलिए कोई प्रलेखन है मुझे लगता है कि आप सही कर रहे हैं, हालांकि - मैं विनिर्देश में हटा देना चाहिए "allocatable" (मुझे लगता है कि ऐसा करने के लिए उत्तर संपादित करेंगे) – DavidW

+0

"हालांकि, प्रतिदेय अभी भी create_hist अंदर निहित इंटरफ़ेस है।" - हाँ, यह लगभग निश्चित रूप से सच है। मुझे वास्तव में फोर्ट्रान को ठीक करने के लिए पर्याप्त रूप से पता नहीं है, लेकिन मैं कृतज्ञतापूर्वक एक सुझाव (या संपादित) स्वीकार करता हूं जो करता है। – DavidW

संबंधित मुद्दे