वैज्ञानिक कार्यक्रमों में फोरट्रान में फ़ंक्शन पॉइंटर्स के साथ कैसे काम करें


11

यहाँ सी में फ़ंक्शन पॉइंटर्स का एक विशिष्ट उपयोग किया गया है। मैं फोरट्रान में कुछ ऐसा ही करना चाहूंगा। मेरे पास कुछ विचार हैं, लेकिन मैं जानना चाहूंगा कि क्या ऐसा करने के लिए कुछ विहित तरीका है।

उपयोगकर्ता द्वारा पारित फ़ंक्शन पॉइंटर्स और संदर्भों को संग्रहीत किया जाता है, फिर बाद में कहा जाता है।

typedef PetscErrorCode (*TSIFunction)(TS,PetscReal,Vec,Vec,Vec,void*);
PetscErrorCode TSSetIFunction(TS ts,Vec res,TSIFunction f,void *ctx);

उपयोगकर्ता के फ़ंक्शन को विभिन्न संदर्भों में उनके संदर्भ का उपयोग करके वापस बुलाया जाता है।

PETSc में, वे स्ट्रिंग -> फ़ंक्शन पॉइंटर टेबल का भी भारी उपयोग करते हैं। सब कुछ एक प्लगइन है, इसलिए उपयोगकर्ता अपने स्वयं के कार्यान्वयन को पंजीकृत कर सकते हैं और वे प्रथम श्रेणी के हैं।

#define PCGAMG "gamg"
  PCRegisterDynamic(PCGAMG         ,path,"PCCreate_GAMG",PCCreate_GAMG);

यह एक "फ़्लिस्ट" में सृजन दिनचर्या को पंजीकृत करता है, फिर PCSetFromOptions () अन्य तरीकों में से किसी एक के द्वारा इस पद्धति को चुनने की क्षमता प्रदान करता है। यदि सिस्टम डायनेमिक लोडिंग का समर्थन करता है, तो आप PCCreate_GAMG प्रतीक पर संकलन-समय की निर्भरता को छोड़ सकते हैं और बस NULL पास कर सकते हैं, तो रन टाइम में साझा लाइब्रेरी में प्रतीक दिखाई देगा।

ध्यान दें कि यह एक "कारखाने" से परे एक कदम है, यह नियंत्रण उपकरण का उलटा है जो मार्टिन फाउलर "सेवा लोकेटर" कहता है।

नोट: यह जेड ब्राउन के साथ मेरे निजी पत्राचार में सामने आया, जहां उन्होंने मुझसे यह सवाल पूछा। मैंने इसे आउटसोर्स करने का फैसला किया और देखा कि लोग क्या जवाब दे सकते हैं।

जवाबों:


5

void *आधुनिक फोरट्रान कोड में अनुकरण करने के लिए स्थानांतरण का उपयोग करने की कोई आवश्यकता नहीं है । इसके बजाय, बस ISO_C_BINDING आंतरिक मॉड्यूल का उपयोग करें , जो सभी मुख्यधारा फोरट्रान कंपाइलरों द्वारा समर्थित है। यह मॉड्यूल फोरट्रान और सी के बीच इंटरफ़ेस के लिए बहुत सरल बनाता है, कुछ बहुत ही मामूली कैविटीज़ के साथ। एक फोरट्रान डेटा और प्रक्रियाओं को क्रमशः सी पॉइंटर्स प्राप्त करने के लिए C_LOCऔर C_FUNLOCकार्यों का उपयोग कर सकता है।

उपरोक्त PETSC उदाहरण के संबंध में, मुझे लगता है कि संदर्भ आमतौर पर उपयोगकर्ता-परिभाषित संरचना के लिए एक संकेतक है, जो कि फोरट्रान में एक व्युत्पन्न डेटा प्रकार के बराबर है। इसका उपयोग करने से निपटने के लिए कोई समस्या नहीं होनी चाहिए C_LOC। से निपटने के लिए अपारदर्शी TSIFunction हैंडल भी बहुत सरल है: बस ISO_C_BINDING डेटा प्रकार का उपयोग करें c_ptr, जो कि void *C. के बराबर है । फोरट्रान में लिखी गई एक लाइब्रेरी का उपयोग कर सकते हैं c_ptrयदि उसे आधुनिक फोरट्रान के सख्त प्रकार की जाँच करने की आवश्यकता है।


ब्रायन, हां, इस बीच, जेड और मैंने कॉलबैक के लिए काफी कुछ समाधान निकाला है , यहां देखें: Fortran90.org/src/best-practices.html#type-casting-in-callbacks , टाइप (c_ptr) खंड संख्या V है
Ondřej íertík

9

आपके प्रश्न में PETSc- विशिष्ट भाषा है (जिसके साथ मैं अपरिचित हूँ) बहुत कुछ है, इसलिए यहाँ एक शिकन हो सकती है जो मुझे समझ में नहीं आ रही है, लेकिन शायद यह आपको प्राप्त करने के लिए उपयोगी होगी शुरू कर दिया है।

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

MODULE xmod

  ABSTRACT INTERFACE
  FUNCTION function_template(n,x) RESULT(y)
      INTEGER, INTENT(in) :: n
      REAL, INTENT(in) :: x(n)
      REAL :: y
  END FUNCTION function_template
  END INTERFACE

CONTAINS

  SUBROUTINE execute_function(n,x,func,y)
    INTEGER, INTENT(in) :: n
    REAL, INTENT(in) :: x(n)
    PROCEDURE(function_template), POINTER :: func
    REAL, INTENT(out) :: y
    y = func(n,x)
  END SUBROUTINE execute_function

END MODULE xmod


PROGRAM xprog

  USE xmod

  REAL :: x(4), y
  PROCEDURE(function_template), POINTER :: func

  x = [1.0, 2.0, 3.0, 4.0]
  func => summation

  CALL execute_function(4,x,func,y)

  PRINT*, y  ! should give 10.0

CONTAINS

  FUNCTION summation(n,x) RESULT(y)
    INTEGER, INTENT(in) :: n
    REAL, INTENT(in) :: x(n)
    REAL :: y
    y = SUM(x)
  END FUNCTION summation

END PROGRAM xprog

जवाब के लिए धन्यवाद। पेट्सक उदाहरण ऊपर भी कुछ आंतरिक डेटा संरचना में फ़ंक्शन पॉइंटर को संग्रहीत करता है, लेकिन मुझे लगता है कि PROCEDURE(function_template), POINTER :: funcआंतरिक रूप से बचाने के लिए यह काफी तुच्छ है ।
ओदनीज íertík

ध्यान दें कि सूचक उस कोड के पते के बजाय एक अपारदर्शी वस्तु है, इसलिए AFAIK सी के साथ इंटरऑपरेबिलिटी नहीं हो सकता है। पेट्सक में, हमें इन चीजों के लिए सी रैपर के लिए फ़ंक्शन पॉइंटर्स की तालिकाओं को बनाए रखना होगा।
मैट नेप्ले

पेट्सक उदाहरण फ़ंक्शन पॉइंटर और संदर्भ दोनों को संग्रहीत करता है (निजी उपयोगकर्ता डेटा जो फ़ंक्शन को वापस बुलाया जाता है)। संदर्भ वास्तव में महत्वपूर्ण है, अन्यथा उपयोगकर्ता ग्लोबल्स को संदर्भित करने जैसी भयानक चीजें करता है। चूंकि इसके बराबर नहीं है void*, उपयोगकर्ता स्वयं लाइब्रेरी फ़ंक्शंस के लिए इंटरफेस लिखने के लिए समाप्त होता है। यदि आप लाइब्रेरी को C में कार्यान्वित करते हैं, तो यह पर्याप्त है, लेकिन यदि आप फोरट्रान में कार्यान्वित करते हैं, तो आपको यह सुनिश्चित करना होगा कि कंपाइलर कभी भी लाइब्रेरी के "डमी" INTERFACE को उपयोगकर्ता के INTERFACE के रूप में न देखे।
जेड ब्राउन

2
void*फोरट्रान के बराबर एक transferविधि है। उपयोग के उदाहरण के लिए यहां देखें । transferविधि के अलावा अन्य 3 दृष्टिकोण "कार्य सरणियाँ", "के बजाय विशिष्ट व्युत्पन्न प्रकार void *" हैं और मॉड्यूल के लिए स्थानीय चर का उपयोग करते हैं।
ओंडे'ज kertík

यह शर्म की बात है कि उपयोगकर्ता को केवल फ़ंक्शन को कॉल करने के transferलिए एक बकवास प्रकार ( character (len=1), allocatable) के साथ चारों ओर चक्कर लगाना पड़ता है ।
जेड ब्राउन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.