2014-11-02 84 views
1

我正在嘗試從Fortran中調用GSL rountine CQUAD。我的想法是編寫一個調用gsl rountine的.c子例程,並依賴於函數和邊界。兩個問題:我對c和fortrans的iso_c_binding知之甚少。我嘗試如下:從Fortran調用GSL例程CQUAD

一個簡單的調用程序(在No output from a Fortran program using the Gnu Scientific Library via a c wrapper類似MSB的職位):

program test 

    use iso_c_binding 

    interface 
     function my_cquad (f,a,b) bind(c) 
     import 
     real (kind=c_double) :: my_cquad 

     interface 
      function f(x) bind(c) 
       import 
       real(kind=c_double) :: f,x 
      end function 
     end interface 

     real (kind=c_double) :: a,b 
     end function my_cquad 
    end interface 

    real (kind=c_double) :: y,a,b 

    a=0. ; b=1. 
    y=my_cquad(g,a,b) 
    print*,y 

    stop 

contains 

    function g(x) bind(C) 
     real(kind=c_double) :: g,x 
     g=sin(x)/x 
     return 
    end function g 

end program test 

的.C子程序(基本上由CQUAD的https://scicomp.stackexchange.com/questions/4730/numerical-integration-handling-nans-c-fortran筆者給出的例子所):

#include <stdio.h> 
#include <gsl/gsl_integration.h> 

double my_cquad (double my_f() , double a , double b ) 
{ 
    gsl_function f; 
    gsl_integration_cquad_workspace *ws = NULL; 
    double res, abserr; 
    size_t neval; 

    /* Prepare the function. */ 
    f.function = my_f; 
    f.params = NULL; 

    /* Initialize the workspace. */ 
    if ((ws = gsl_integration_cquad_workspace_alloc(200)) == NULL) { 
     printf("call to gsl_integration_cquad_workspace_alloc failed.\n"); 
     abort(); 
     } 

    /* Call the integrator. */ 
    if (gsl_integration_cquad(&f, a , b , 1.0e-10 , 1.0e-10 , ws , &res , &abserr , &neval) != 0) { 
     printf("call to gsl_integration_cquad failed.\n"); 
     abort(); 
     } 

    /* Free the workspace. */ 
    gsl_integration_cquad_workspace_free(ws); 

    /* Bye. */ 
    return res; 
} 

單獨的.c子程序似乎工作正常。這可以通過測試:

double g (double x) 
{ 
return sin(x)/x; 
} 

int main() { 
double y; 
y=my_cquad(g,0.,1.); 
printf("y: %2.18f\n", y); 

return 0; 
} 

但與.F90調用程序一起,在它編譯的時刻,但在運行時我得到一個分段錯誤,我不完全得到。

此外,根據Fortran類型的函數,創建一個c型函數的某種包裝器當然會很好。我正在考慮類似的東西:

function f_to_c(f) bind(c) 
    real(kind=c_double) :: f_to_c 
    real(kind=8) :: f 
    f_to_c=real(f,kind=c_double) 
end function 

但是,這不覆蓋虛擬變量。

在此先感謝和非常抱歉的代碼量。

+1

不要重新發明輪子:使用fgsl(http://www.lrz.de/services/software/mathematik/gsl/fortran/)。它是完整的(包括cquad),並且效果很好。 – 2014-11-03 00:50:44

+2

@ViniciusMiranda它解決了,但是當一個簡單的接口塊就足夠了,我去爲它而不是安裝完整的軟件包。同樣,我使用我自己的非常簡單的接口'pthread_create'和'pthread_join',而不是使用現有的Fortran POSIX包,研究其安裝並將其保存在需要我的代碼編譯的所有計算機上。 – 2014-11-03 09:08:43

+0

@ViniciusMiranda謝謝,這肯定是首先想到的。但是,在編譯fgsl時,所有例程的make check都失敗了。到目前爲止,筆者沒有回答我的問題。正如Vladimir F所說,對於一個例行公事,我不認爲需要安裝一個完整的軟件包。除此之外,我喜歡有更多的控制權,特別是如果標準軟件包有bug的話。 – PeMa 2014-11-03 13:02:13

回答

3

請注意,根據Fortran標準,內部函數不應具有bind(C)屬性。我把這個功能移到了一個模塊中。

ab必須通過值被傳遞給my_cquadx到綜合功能:

測試:

> gfortran my_cquad.c test_cquad.f90 -lgsl -lopenblas 
> ./a.out 
    0.94608307036718275 

這是一個包裝的正常Fortran函數的例子(請不要使用kind=8在另一個問題中解釋的很多原因):

module functions_to_integrate 
    use iso_fortran_env 
    use iso_c_binding 


    integer, parameter :: wp = real64 
contains 

    pure function g(x) 
     real(kind=wp) :: g 
     real(kind=wp), intent(in) :: x 
     g = sin(x)/x 
    end function g 

    function g_to_c(x) bind(C) 
     real(kind=c_double) :: g_to_c 
     real(kind=c_double), value :: x 
     g_to_c = real(g(x),kind=c_double) 
    end function 

end module 

program test 

    use iso_c_binding 

    use functions_to_integrate 

    interface 
     function my_cquad (f,a,b) bind(c) 
      import 
      real (kind=c_double) :: my_cquad 

      interface 
      function f(x) bind(c) 
       import 
       real(kind=c_double) :: f 
       real(kind=c_double), value :: x 
      end function 
      end interface 

      real (kind=c_double), value :: a,b 
     end function my_cquad 
    end interface 

    real (kind=c_double) :: y,a,b 

    a = 0 ; b = 1 
    y = my_cquad(g_to_c,a,b) 

    print *,y 

end program test 

P.S.我還在結束之前刪除了您的stopreturn聲明。不知何故,它總是讓我發瘋,但那可能只是我的強迫症。我很習慣從遠古時代的舊節目中看到它。

P.P.S:您可能希望看到由Vincius Miranda http://www.lrz.de/services/software/mathematik/gsl/fortran/鏈接的FGSL接口包。我知道這一點,但我主要嘗試指出錯誤,以便您可以自己製作類似的接口,而不需要現成的包裝。

+0

謝謝!但我有一些問題。我猜'g(x)'通常不需要是純粹的?你能提供一個鏈接到'kind = 8'的問題嗎?我通常在我的程序中也有'複雜'變量。有了'wp = 8'之類的東西,我就可以輕鬆地在精度(如果需要)之間切換, '真實(wp)',複雜(wp)','1._wp'等。這種行爲與'wp = real64'相同嗎?和'c _...'變量有什麼相似之處嗎? – PeMa 2014-11-03 13:16:38

+1

@PeMa我把它變得純粹,因爲它在那裏很方便,但它不一定是純粹的。你應該理解類型符號以及爲什麼數字4和8是不可移植的。閱讀http://stackoverflow.com/a/856243/721644 http://stackoverflow.com/a/10521611/721644和http://stackoverflow.com/questions/3170239/fortran-integer4-vs-integer4-vs- integerkind-4/3170438 – 2014-11-03 13:24:19

+1

@PeMa這也是體面的http://fortranwiki.org/fortran/show/Real+precision。注意'wp = real64',你可以很容易地把它改成'wp = real32'。無論在哪裏,都要改變8到4。 – 2014-11-03 13:26:42