加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Windows下Fortran编译ODEPack库及使用方法

(2013-08-26 08:37:02)
标签:

fortran

gfortran

ode

odepack

it

分类: 010101
ODEPack用 Fortran 77 写成,是一个非常经典的 ODE 求解器集合。这里主要描述如何编译网上的 ODEPack 代码,并且将其集成到自己的程序中。
 
本文使用环境如下:
 
操作系统版本:Windows 8
使用的编译器:gfortran (GCC版本4.6.2 MinGW环境)
 
1)下载ODEPack
 
可以到官网(http://www.netlib.org/odepack/)下载源码。
 
这里还有个更现代的版本(http://www.shocksolution.com/math_tools/odepack/),多了几个示例和文档。如果是 Linux 系统可以用自带的 Makefile ,我们这里是windows系统就用不上了。
 
下载完成后解压,打开 cmd 或者 MinGW Shell 一路 cd 进入源代码文件夹。
 
2)编译
 
ODEPack 别看打包了那么多 ODE Solver,其实源代码组成非常简单,总共六个文件,分别对应单精度和双精度:
 
双精度文件: opkda1.f opkda2.f opkdmain.f
单精度文件: opksa1.f opksa2.f opksmain.f
 
细心的你肯定已经发现其实就是 opk 后面的 d (double) 和 s (single)的区别。正常情况下其实我们只需要用一个版本,所以其实这六个文件中有三个对我们来说是没用的。
 
我们现在要做的就是把 f 文件编译成静态或者动态链接库,我选择编译双精度文件。
 
首先就是把 f 文件编译成 o 文件:
 
gfortran -c *.f
 
接着我们选择编译静态或者动态链接库:
静态链接库:
 
ar crv libodepack.a opkda1.o opkda2.o opkdmain.o
 
 
动态链接库:
 
gfortran opkda1.o opkda2.o opkdmain.o -shared -o libodepack.dll
 
这样我们就得到了静态或者动态链接库文件 libodepack.a 或者 libodepack.dll 。
 
3)使用:
 
静态和动态链接库使用方法类似,不同的是静态链接库只要连接一下就行,里面的代码会被包含到目标程序里面去,动态链接库里的代码还是独立存在,需要编译后把 dll 文件拷贝到目标程序文件下。
 
这里我们使用一个现代版本所用的 f95 示例做演示。下面是源代码,方便从官网下代码的同学测试。
 
example.f95:
! *Examples:
! The following is a simple example problem, with the coding needed
! for its solution by DLSODE. The problem is from chemical kinetics,
! and consists of the following three rate equations:
       dy1/dt = -.04*y1 + 1.E4*y2*y3
       dy2/dt = .04*y1 - 1.E4*y2*y3 - 3.E7*y2**2
       dy3/dt = 3.E7*y2**2
 
! on the interval from t = 0.0 to t = 4.E10, with initial conditions
! y1 = 1.0, y2 = y3 = 0. The problem is stiff.
! The following coding solves this problem with DLSODE, using
! MF = 21 and printing results at t = .4, 4., ..., 4.E10.  It uses
! ITOL = 2 and ATOL much smaller for y2 than for y1 or y3 because y2
! has much smaller values.  At the end of the run, statistical
! quantities of interest are printed.
 
EXTERNAL FEX, JEX
INTEGER IOPT, IOUT, ISTATE, ITASK, ITOL, IWORK(23), LIW, LRW, MF, NEQ
DOUBLE PRECISION ATOL(3), RTOL, RWORK(58), T, TOUT, Y(3)
 
NEQ = 3                 ! number of first-order ODE's
 
Y(1) = 1.D0             ! values of y(t) at t=t1
Y(2) = 0.D0
Y(3) = 0.D0
 
T = 0.D0                ! initial value of independent variable t
TOUT = .4D0             ! next value of independent variable t
ITOL = 2                ! 1 indicates ATOL is scalar, 2 indicates ATOL is array
RTOL = 1.D-4            ! Relative tolerance
 
ATOL(1) = 1.D-6         ! Absolute tolerance for each i in Y(i)
ATOL(2) = 1.D-10
ATOL(3) = 1.D-6
 
ITASK = 1               ! Indicates that DLSODE is to compute output values of y
ISTATE = 1              ! ISTATE=1 for first call, ISTATE=2 for subsequent calls
                        ! Automatically updated to 2 if DLSODE was successful
 
IOPT = 0                ! IOPT=0 for no optional inputs, IOPT=1 for optional inputs
LRW = 58                ! Length of real work array
LIW = 23                ! Length of integer work array
MF = 21                 ! Method flag.  Possible values are:
                        ! 10  Nonstiff (Adams) method, no Jacobian used.
                        ! 21  Stiff (BDF) method, user-supplied full Jacobian.
                        ! 22  Stiff method, internally generated full Jacobian.
                        ! 24  Stiff method, user-supplied banded Jacobian.
                        ! 25  Stiff method, internally generated banded Jacobian.
 
20  FORMAT(' At t =',D12.4,'   y =',3D14.6)
 
DO IOUT = 1,12
    CALL DLSODE (FEX, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK, ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JEX, MF)
    WRITE(6,20 T, Y(1), Y(2), Y(3)
    IF (ISTATE .LT. 0 GO TO 80
    TOUT = TOUT*10.D0               ! Next time step
END DO
 
WRITE(6,60 IWORK(11), IWORK(12), IWORK(13)
60  FORMAT(/' No. steps =',i4,',  No. f-s =',i4,',  No. J-s =',i4)
STOP
 
! error handling
80  WRITE(6,90 ISTATE
90  FORMAT(///' Error halt.. ISTATE =',I3)
STOP
END
 
SUBROUTINE  FEX (NEQ, T, Y, YDOT)
    ! Set array Ydot
    INTEGER  NEQ
    DOUBLE PRECISION  T, Y(3), YDOT(3)
    YDOT(1) = -.04D0*Y(1) + 1.D4*Y(2)*Y(3)
    YDOT(3) = 3.D7*Y(2)*Y(2)
    YDOT(2) = -YDOT(1) - YDOT(3)
    RETURN
END
 
SUBROUTINE  JEX (NEQ, T, Y, ML, MU, PD, NRPD)
    ! Set Jacobian matrix
    INTEGER  NEQ, ML, MU, NRPD
    DOUBLE PRECISION  T, Y(3), PD(NRPD,3)
    PD(1,1) = -.04D0
    PD(1,2) = 1.D4*Y(3)
    PD(1,3) = 1.D4*Y(2)
    PD(2,1) = .04D0
    PD(2,3) = -PD(1,3)
    PD(3,2) = 6.D7*Y(2)
    PD(2,2) = -PD(1,2) - PD(3,2)
 
      Uncomment lines below to dump Jacobian values for debugging
   DO I=1,3
       WRITE (6,100) PD(I,1), PD(I,2), PD(I,3)
   ENDDO
   100  FORMAT (es12.5, ' ', es12.5, ' ', es12.5)
!
   WRITE (6,100) Y(1), Y(2), Y(3)
 
    RETURN
END
 
假设静态和动态链接库都放到和源代码同级的 lib 文件夹中,那么编译这个程序所用的方式为:
 
gfortran example.f95 -o example -L./lib -lodepack
 
如果是静态链接库那么直接执行 example.exe 就可以看到结果,动态链接库在编译后还需要把 libodepack.dll 拷贝到同文件夹下,否则会出错。
 
下面如果有机会的话我会给出ODEPack的使用教程。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有