বরাদ্দযোগ্য এবং ধরে নেওয়া আকারের অ্যারে সহ 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। নোট যে ysubroutine এর শরীরের মধ্যে বরাদ্দ এবং deallocated হয়।

আমি যখন এটি সংকলন করি 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মান রয়েছে0f । আমি ধরে নিয়েছি যে f2pyএই পরিস্থিতিটি সঠিকভাবে পরিচালনা করতে আমি কিছু শিরোনাম জাদুটি অনুপস্থিত ।

উপরোক্ত সাবরোটিনকে পাইথনের সাথে যুক্ত করার সর্বোত্তম উপায় কী? আমি দৃ strongly়ভাবে সাবউটাইন নিজেই পরিবর্তন না করতে পছন্দ করব।


ম্যাট, আপনি কি ওঁদ্রেজ সার্তিকের সেরা অনুশীলন গাইড, বিশেষত, পাইথন বিভাগের সাথে ইন্টারফেসিংয়ের সাথে পরিচিত ? আমরা পাইক্লাওর জন্য অনুরূপ ইন্টারফেসিং ইস্যু নিয়ে আলোচনা করেছি এবং এখনও এটিকে সমাধান করেছি না :)
অ্যারন আহমদিয়া

উত্তর:


23

আমি এফ 2 পি ইন্টার্নালগুলির সাথে খুব বেশি পরিচিত নই, তবে ফোর্টরান মোড়ানোর সাথে আমি খুব পরিচিত। F2py কেবল নীচের কিছু বা সমস্ত জিনিস স্বয়ংক্রিয় করে তোলে।

  1. আপনাকে প্রথমে সি-তে রফতানি করতে হবে আইসো_সি_বাইন্ডিং মডিউলটি ব্যবহার করে, উদাহরণস্বরূপ এখানে বর্ণিত:

    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(:)

    কারণ সি ভাষা নিজেই এই জাতীয় অ্যারে সমর্থন করে না। 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যাচ্ছিলাম তবে আমি কিছু বরাদ্দ করতে চেয়েছি (আমার আসল কোডটিতে তুচ্ছ বরাদ্দ রয়েছে)। যদিও আমি অন্যান্য পয়েন্টগুলির অনেকগুলি সম্পর্কে জানতাম না। দেখে মনে হচ্ছে আমার কোনও ধরণের Fortran90 সেরা অভ্যাস গাইডের দিকে নজর দেওয়া উচিত .... পুরো উত্তরের জন্য ধন্যবাদ!
এমরোকলিন

নোট করুন যে আজকের ফরট্রান সংকলকগুলি ব্যবহার করে আপনি F77 ঠিক একইভাবে মুড়ে রাখছেন --- একটি সাধারণ iso_c_b ਬਾਈেন্ডিং র‌্যাপার লিখে এবং এখান থেকে উত্তরাধিকারের 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 alচ্ছিক করে তোলে। অজগর হিসাবে প্রদর্শিত হওয়ার সাথে সাথে ফাংশনের ডক্ট্রিংটি নিম্নরূপ:

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 ** এনও পাস করতে হবে।
অ্যালেও
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.