English 中文(简体)
Fortran 使用Fortran 90号堡垒用轨迹 6 维集成
原标题:6 dimensional integral by Trapezoid in Fortran using Fortran 90

我需要以有效的方式使用90堡的Trapezoid 来计算六维集成体。这里是我要做的一个例子:

"https://i.sstatic.net/U3W1Z.png" alt="整体表达式"/ >

如果 F 是数值函数( 如非分析), 将在 x1 到 x6 变量之间整合。 我最初编码了一个维次常规 :

  SUBROUTINE trapzd(f,mass,x,nstep,deltam) 
      INTEGER nstep,i
      DOUBLE PRECISION mass(nstep+1),f(nstep+1),x,deltam
      x=0.d0
      do i=1,nstep
          x=x+deltam*(f(i)+f(i+1))/2.d0
      end do
  return
  END

但是,我也不知道如何将这个范围扩大到6个维度。 我可以再使用6次,每个维度一次,还是写一个新的子例程?

如果您有类似Python、MATLAB或Java等另一种语言的“完整编码”版本(没有图书馆/API使用)

P.S.这不是学校作业,我是生物医学博士生,这是我在模拟干细胞活动方面的研究的一部分。我没有深厚的编码和数学背景。

提前感谢您

问题回答

您可以查看 GNU 科学图书馆 (GSL) 的 Monte Carlo 整合章节。 它既是图书馆,也是开放源码,可以学习源代码。

在计算上,对多个整体体的直接评估具有挑战性,最好使用蒙特卡洛(Monte Carlo),或许可以使用重要取样,但粗略的结合有时对方法的验证很有意义。

我使用的集成常规是卢克莫1970年写的“ Quadmo ” 。 我把它重新编译并放入一个模块。 Quadmo 改进网格以获得所要求的集成精度。 这是一个使用 Quadmo 的 n- 维集成程序 。

这是对程序的验证, 使用一个高斯语程序, 以0. 5为中心, 以SD 0.1为主, 在 nDim 到 6 的所有维度上, 使用 G95 编译。 它在几秒钟内运行 。

  nDim ans       expected       nlvl
     1 0.249     0.251      2
     2 6.185E-02 6.283E-02  2  2
     3 1.538E-02 1.575E-02  2  2  2
     4 3.826E-03 3.948E-03  2  2  2  2
     5 9.514E-04 9.896E-04  2  2  2  2  2
     6 2.366E-04 2.481E-04  2  2  2  2  2  2

这是代码:

!=======================================================================
      module QuadMo_MOD
      implicit none
      integer::QuadMo_MinLvl=6,QuadMo_MaxLvl=24
      integer,dimension(:),allocatable::QuadMo_nlvlk
      real*8::QuadMo_Tol=1d-5
      real*8,save,dimension(:),allocatable::thet
      integer,save::nDim

      abstract interface
        function QuadMoFunct_interface(thet,k)
           real*8::QuadMoFunct_interface
           real*8,intent(in)::thet
           integer,intent(in),optional::k
        end function
      end interface

      abstract interface
        function MultIntFunc_interface(thet)
           real*8::MultIntFunc_interface
           real*8,dimension(:),intent(in)::thet
        end function
      end interface

      procedure(MultIntFunc_interface),pointer :: stored_func => null()

      contains

!----------------------------------------------------------------------
      recursive function quadMoMult(funct,lower,upper,k) result(ans) 
  ! very powerful integration routine written by Luke Mo
  !  then at the Stanford Linear Accelerator Center circa 1970
  ! QuadMo_Eps is error tolerance  
  ! QuadMo_MinLvl determines initial grid of 2**(MinLvl+1) + 1 points
  !  to avoid missing a narrow peak, this may need to be increased.  
  ! QuadMo_Nlvl returns number of subinterval refinements required beyond
  ! QuadMo_MaxLvl

  ! Modified by making recursive and adding argument k
  !  for multiple integrals ([email protected])
      real*8::ans
      procedure(QuadMoFunct_interface) :: funct
      real*8,intent(in)::lower,upper
      integer,intent(in),optional::k
      real*8::Middle,Left,Right,eps,est,fLeft,fMiddle,fRight
     & ,fml,fmr,rombrg,coef,estl,estr,estint,area,abarea
      real*8::valint(50,2), Middlex(50), Rightx(50), fmx(50), frx(50)
     & ,fmrx(50), estrx(50), epsx(50)
      integer retrn(50),i,level
      level = 0
      QuadMo_nlvlk(k) = 0
      abarea = 0
      Left = lower
      Right = upper
      if(present(k))then
         fLeft = funct(Left,k)
         fMiddle = funct((Left+Right)/2,k)
         fRight = funct(Right,k)
      else
         fLeft = funct(Left)
         fMiddle = funct((Left+Right)/2)
         fRight = funct(Right)
      endif
      est = 0
      eps = QuadMo_Tol
  100 level = level+1
      Middle = (Left+Right)/2
      coef = Right-Left
      if(coef.ne.0) go to 150
      rombrg = est
      go to 300
  150 continue
      if(present(k))then
         fml = funct((Left+Middle)/2,k)
         fmr = funct((Middle+Right)/2,k)
      else
         fml = funct((Left+Middle)/2)
         fmr = funct((Middle+Right)/2)
      endif
      estl = (fLeft+4*fml+fMiddle)*coef
      estr = (fMiddle+4*fmr+fRight)*coef
      estint = estl+estr
      area= abs(estl)+ abs(estr)
      abarea=area+abarea- abs(est)
      if(level.ne.QuadMo_MaxLvl) go to 200
      QuadMo_nlvlk(k) = QuadMo_nlvlk(k)+1
      rombrg = estint
      go to 300
  200 if(( abs(est-estint).gt.(eps*abarea)).or.
     1(level.lt.QuadMo_MinLvl))  go to 400
      rombrg = (16*estint-est)/15
  300 level = level-1
      i = retrn(level)
      valint(level, i) = rombrg
      go to (500, 600), i
  400 retrn(level) = 1
      Middlex(level) = Middle
      Rightx(level) = Right
      fmx(level) = fMiddle
      fmrx(level) = fmr
      frx(level) = fRight
      estrx(level) = estr
      epsx(level) = eps
      eps = eps/1.4d0
      Right = Middle
      fRight = fMiddle
      fMiddle = fml
      est = estl
      go to 100
  500 retrn(level) = 2
      Left = Middlex(level)
      Right = Rightx(level)
      fLeft = fmx(level)
      fMiddle = fmrx(level)
      fRight = frx(level)
      est = estrx(level)
      eps = epsx(level)
      go to 100
  600 rombrg = valint(level,1)+valint(level,2)
      if(level.gt.1) go to 300
      ans  = rombrg /12
      end function quadMoMult
!-----------------------------------------------------------------------
      recursive function MultInt(k,func) result(ans)
      ! MultInt(nDim,func) returns multi-dimensional integral from 0 to 1
      !  in all dimensions of function func
      !  variable QuadMo_Mod: nDim needs to be set initially to number of dimensions      
      procedure(MultIntFunc_interface) :: func
      real*8::ans
      integer,intent(in)::k

      stored_func => func

      if(k.eq.nDim)then
         if(allocated(thet))deallocate(thet)
         allocate (thet(nDim))
         if(allocated(QuadMo_nlvlk))deallocate(QuadMo_nlvlk)
         allocate(QuadMo_nlvlk(nDim))
      endif

      if(k.eq.0)then
         ans=func(thet)
         return
      else
         ans=QuadMoMult(MultIntegrand,0d0,1d0,k)
      endif
      end function MultInt
!-----------------------------------------------------------------------
      recursive function MultIntegrand(thetARG,k) result(ans)
      real*8::ans
      real*8,intent(in)::thetARG
      integer,optional,intent(in)::k

      if(present(k))then
         thet(k)=thetARG
      else
         write(*,*) MultIntegrand: not expected, k not present! 
         stop
      endif
      ans=MultInt(k-1,stored_func)
      end function MultIntegrand
!-----------------------------------------------------------------------
      end module QuadMo_MOD
!=======================================================================
      module test_MOD
      use QuadMo_MOD
      implicit none

      contains

!----------------------------------------------------------------------- 
      real*8 function func(thet) ! multidimensional function
      ! this is the function defined in nDim dimensions
      !  in this case a Gaussian centered at 0.5 with SD 0.1
      real*8,intent(in),dimension(:)::thet
      func=exp(-sum(((thet-5d-1)/1d-1)
     & *((thet-5d-1)/1d-1))/2)
      end function func
!----------------------------------------------------------------------- 
      end module test_MOD 
!=======================================================================
      ! test program to evaluate multiple integrals 
      use test_MOD
      implicit none 
      real*8::ans 

      ! these values are set for speed, not accuracy
      QuadMo_MinLvl=2
      QuadMo_MaxLvl=3
      QuadMo_Tol=1d-1

      write(*,*)      nDim ans       expected       nlvl 
      do nDim=1,6
         ! expected answer is (0.1 sqrt(2pi))**nDim
         ans=MultInt(nDim,func)
         write(*, (i10,2(1pg10.3),999(i3)) )nDim,ans,(0.250663)**nDim
     &    ,QuadMo_nlvlk
      enddo
      end
!-----------------------------------------------------------------------
double MultInt(int k);
double MultIntegrand(double thetARG, int k);
double quadMoMult(double(*funct)(double, int), double lower, double upper, int k);
double funkn(double *thet);

int QuadMo_MinLvl = 2;
int  QuadMo_MaxLvl = 3;
double QuadMo_Tol = 0.1;
int *QuadMo_nlvlk;
double *thet;
int nDim;


//double MultInt(int k, double(*func)(double *))
double MultInt(int k)
{

//MultInt(nDim, func) returns multi - dimensional integral from 0 to 1
//in all dimensions of function func
    double ans;

    if (k == 0) 
    {
        ans = funkn(thet);
    }
    else
    {
        ans = quadMoMult(MultIntegrand, 0.0, 1.0, k); //limits hardcoded here
    }
    return ans;
}


double MultIntegrand(double thetARG, int k)
{
    double ans;

    if (k > 0)
        thet[k] = thetARG;
    else
        printf("
***MultIntegrand: not expected, k not present!***
");

        //Recursive call
    //ans = MultInt(k - 1, func);
    ans = MultInt(k - 1);
    return ans;
}


double quadMoMult(double(*funct)(double, int), double lower, double upper, int k)
{
    //Integration routine written by Luke Mo
    //Stanford Linear Accelerator Center circa 1970
    //QuadMo_Eps is error tolerance
    //QuadMo_MinLvl determines initial grid of 2 * *(MinLvl + 1) + 1 points
    //to avoid missing a narrow peak, this may need to be increased.
    //QuadMo_Nlvl returns number of subinterval refinements required beyond
    //QuadMo_MaxLvl

    //Modified by making recursive and adding argument k
    //for multiple integrals([email protected])

    double ans;
    double Middle, Left, Right, eps, est, fLeft, fMiddle, fRight;
    double fml, fmr, rombrg, coef, estl, estr, estint, area, abarea;
    double valint[51][3], Middlex[51], Rightx[51], fmx[51], frx[51];  //Jack up arrays
    double fmrx[51], estrx[51], epsx[51];
    int retrn[51];
    int i, level;

    level = 0;
    QuadMo_nlvlk[k] = 0;
    abarea = 0.0;
    Left = lower;
    Right = upper;
    if (k > 0)
    {
        fLeft = funct(Left, k);
        fMiddle = funct((Left + Right) / 2, k);
        fRight = funct(Right, k);
    }
    else
    {
        fLeft = funct(Left,0);
        fMiddle = funct((Left + Right) / 2,0);
        fRight = funct(Right,0);
    }
    est = 0.0;
    eps = QuadMo_Tol;
l100:
    level = level + 1;
    Middle = (Left + Right) / 2;
    coef = Right - Left;
    if (coef != 0.0)
        goto l150;
    rombrg = est;
    goto l300;
l150:
    if (k > 0)
    {
        fml = funct((Left + Middle) / 2.0, k);
        fmr = funct((Middle + Right) / 2.0, k);
    }
    else
    {
        fml = funct((Left + Middle) / 2.0, 0);
        fmr = funct((Middle + Right) / 2.0, 0);
    }
    estl = (fLeft + 4 * fml + fMiddle)*coef;
    estr = (fMiddle + 4 * fmr + fRight)*coef;
    estint = estl + estr;
    area = abs(estl) + abs(estr);
    abarea = area + abarea - abs(est);
    if (level != QuadMo_MaxLvl)
        goto l200;
    QuadMo_nlvlk[k] = QuadMo_nlvlk[k] + 1;
    rombrg = estint;
    goto l300;
l200:
    if ((abs(est - estint) > (eps*abarea)) || (level < QuadMo_MinLvl))
        goto l400;
    rombrg = (16 * estint - est) / 15;
l300:
    level = level - 1;
    i = retrn[level];
    valint[level][i] = rombrg;
    if (i == 1)
        goto l500;
    if (i == 2)
        goto l600;
l400:
    retrn[level] = 1;
    Middlex[level] = Middle;
    Rightx[level] = Right;
    fmx[level] = fMiddle;
    fmrx[level] = fmr;
    frx[level] = fRight;
    estrx[level] = estr;
    epsx[level] = eps;
    eps = eps / 1.4;
    Right = Middle;
    fRight = fMiddle;
    fMiddle = fml;
    est = estl;
    goto l100;
l500:
    retrn[level] = 2;
    Left = Middlex[level];
    Right = Rightx[level];
    fLeft = fmx[level];
    fMiddle = fmrx[level];
    fRight = frx[level];
    est = estrx[level];
    eps = epsx[level];
    goto l100;
l600:
    rombrg = valint[level][1] + valint[level][2];
    if (level > 1)
        goto l300;
    ans = rombrg / 12.0;
    return ans;
}


double funkn(double *thet)
{
    //in this case a Gaussian centered at 0.5 with SD 0.1
    double *sm;
    double sum;
    sm = new double[nDim];
    sum = 0.0;

    for (int i = 1; i <= nDim; i++) 
    {
        sm[i] = (thet[i] - 0.5) / 0.1;
        sm[i] *= sm[i];
        sum = sum + sm[i];
    }
    return exp(-sum / 2.0);
}


int main() {

    double ans;

    printf("
nDim ans       expected       nlvl
");
    for (nDim = 1; nDim <= 6; nDim++)
    {
        //expected answer is(0.1 sqrt(2pi))**nDim
        QuadMo_nlvlk = new int[nDim + 1];  //array for x values
        thet = new double[nDim + 1];  //array for x values
        ans = MultInt(nDim);
        printf("
 %d %f %f ", nDim, ans, pow((0.250663),nDim));
        for (int j=1; j<=nDim;  j++)
            printf("   %d ", QuadMo_nlvlk[nDim]);
        printf("
");
    }

    return 0;

}

在全球宣布相关参数

int QuadMo_MinLvl = 2;
int  QuadMo_MaxLvl = 3;
double QuadMo_Tol = 0.1;
int *QuadMo_nlvlk;
double *thet;
int nDim;

这种编码比模糊的古老堡垒编码要清楚得多,

有更好的算法 使用适应技术 处理表面等的奇特性...





相关问题
How do I fix this Fortran text parser for Lapack within Gem5

After about an hour, I need to ask for some help. I ve downloaded the math benchmark Lapack to run within a few CPU configurations for the simulation tool Gem5, which lets you build X86 computers and ...

gfortran, DLL, underscore

I want to access some subroutines from a third party DLL. The functions use STDCALL as the calling convention. Running dumpbin /export foo.dll gives me something like: ... 7 6 ...

Getting started with a new code in an unfamiliar language

I m starting a new project in a language I m less familiar with (FORTRAN) and am in the discovery phase. Normally reading through and figuring out code is a fairly simple task, however, this code ...

assigning values to an integer array within a Fortran module

I have a module in Fortran called QFoo. It defines a type QFooType. I want to initialize all the elements of integer array is_n to 0 and want to do it within the module. Could someone help? Thank ...

WinDbg and Intel Visual Fortran

Has anyone used WinDbg to debug an Intel Visual Fortran routine? If I have the Fortran source file that crashes with an AccViol, how can I use WinDbg to determine the line that is crashing?

converting MATLAB code to Fortran [closed]

I a medical researcher with code written in MATLAB 2009b that runs very slowly because of a self-referential loop (not sure of the programming lingo here), i.e., the results of the first iteration is ...

热门标签