在C++中混编调用CHEMKIN

填周六的坑,CHEMKIN是一个燃烧经常使用的Fortran代码包。笔者当前的代码为C++的MPI并行代码,为了在代码中使用CHEMKIN的模块,需要进行C++和Fortran的混编。

基础的混编测试可以查看前一篇
https://blog.csdn.net/qq_40583925/article/details/123024724

调试花了几天的时间,这里先讲需要注意的点,然后直接贴代码~

编译选项的使用

前面已经遇到过C++代码混编和C代码混编不同的问题,解决方案便是使用extern "C"功能,指示编译器将一小块代码按照C语言的方式链接。这个功能的详细介绍有几个讲得比较好的链接推荐

https://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html

https://baike.baidu.com/item/extern%20%22C%22/15267013?fr=aladdin

https://blog.csdn.net/qq_24282081/article/details/87530239

但是使用过程中还有额外的问题需要注意,就是使用extern "C"的代码在调用C++中的库时,会出现这样的报错
在C++中混编调用CHEMKIN_第1张图片
原因可以参考这个博客
https://blog.csdn.net/kittaaron/article/details/8101391

实际上是我们指定了C语言的方式链接后,默认链接的库文件变成了libstdc++.so,而不是默认的libc.so,故需要特殊指明

同理,如果混编代码中想要调用fortran的函数,编译器也无法找到,也需要指定

故一定要添加选项

-lstdc++ -lgfortran

数组的使用

前几天的博客中均为单个变量的数据传递,但是实际使用过程中会使用到数组,因此也需要给定数组的传递。因为Fortran需要传址,直接用数组的地址即可。

#include 
#ifdef __cplusplus
extern "C"{
#endif

void mcinit_(int *,int *,int *,int *,int *,double *);

#ifdef __cplusplus
}
#endif

extern int IData[60];
extern double FData[3000];

void Init(){
     int LINKTP = 35;
     int LOUT = 6;
     int LENIMC = 60;
     int LENRMC = 3000;

     mcinit_(&LINKTP,&LOUT,&LENIMC,&LENRMC,IData,FData);
}

其中IDataFData即为数组。

代码实现

我们当前要调用的是TranLib.F这个CHEMKIN里面的函数库,他先将tran.bin这个二进制的Linking File读入,存入自己的浮点和整型数组中。然后供其中的各种函数使用。

即需要先使用MCINIT函数初始化,然后调用具体的函数例如MCAVIS即可。

我们给出一个Fortran代码调用的例子:

program TranlibTest
      implicit double precision (A-H,O-Z), integer(I-N)
      character VERS*16,PREC*16
      logical KERR
      parameter (LINKTP=35)
      DIMENSION IData(60)
      DIMENSION FData(3000)
      DIMENSIOn X(10)
      open(LINKTP,form='unformatted',status='unknown',
     1            file='tran.bin')

      rewind LINKTP
      read(LINKTP,ERR=999) VERS,PREC,KERR
      read(LINKTP,ERR=999) LI,LR,NO,NKK,NLITE

      write(6,*) VERS,PREC,KERR
      write(6,*) LI,LR,NO,NKK,NLITE

      call MCINIT(LINKTP,6,60,3000,IData,FData)

c     给定一个初始组分
      do n = 1,10
         X(n) = 0.0d0
      end do
      X(1) = 1.0d0

c     给定温度
      T = 300.0d0

c     计算混合物的粘性      
      call MCAVIS(T,X,FData,vismix)
c     注意当前粘性单位为GM/CM*S GM为克的的缩写
c     1GM/CM*S = 0.1 kg/m*s
      write(6,*) vismix*0.1d0

999   CONTINUE
      end

本来这需要在fortran代码中打开文件tran.bin,然后将文件流编号LINKTP传入。这里直接对MCINIT.F进行简单的改写,让函数内部打开这个文件。

...
C
      DIMENSION IMCWRK(*), RMCWRK(*)
      CHARACTER*16 VERS, PREC
      LOGICAL IOK, ROK, KERR
      COMMON /MCCONS/ VERS, PREC, KERR, LENI, LENR
C
      COMMON /MCMCMC/ RU, PATMOS, SMALL, NKK, NO, NLITE, INLIN, IKTDIF,
     1                IPVT, NWT, NEPS, NSIG, NDIP, NPOL, NZROT, NLAM,
     2                NETA, NDIF, NTDIF, NXX, NVIS, NXI, NCP,
     3                NCROT, NCINT, NBIND, NEOK, NSGM,
     4                NAST, NBST, NCST, NXL, NR, NWRK, K3

c     将打开文件的操作放在了这里
      open(LINKMC,form='unformatted',status='unknown',
     1            file='tran.bin')

C
C
C         THE FOLLOWING NUMBER SMALL IS USED IN THE MIXTURE DIFFUSION
C        COEFFICIENT CALCULATION.  ITS USE ALLOWS A SMOOTH AND WELL
C        DEFINED DIFFUSION COEFFICIENT AS THE MIXTURE APPROACHES A
C        PURE SPECIES, EVEN THOUGH STRICTLY SPEAKING THERE DOES NOT
...

然后写好C++的代码,main.cpp调用Init.cppGetVis.cpp分别调用MCINIT初始化,以及调用MCAVIS计算粘性。而这两个函数又会调用另外几个CHMEKIN中的函数MCEPSG,MCLEN,MCEVAL。贴代码如下:

//main.cpp
#include 
using namespace std;

int IData[60];
double FData[3000];

double GetVis();
void Init();

int main(){
    Init();
    cout<<"Init Finished"<
#ifdef __cplusplus
extern "C"{
#endif

void mcavis_(double *,double *,double *,double *);

#ifdef __cplusplus
}
#endif

extern int IData[60];
extern double FData[3000];

double GetVis(){
    double T;
    double X[10];
    double vismix;

    //给定一个组分
    for (int n=0;n<10;n++){
       X[n] = 0.0;
    }
    X[0] = 1.0;

    //给定温度
    T = 300.0;

    mcavis_(&T,X,FData,&vismix);

    return vismix;
}

最终编译运行得到结果如下:
在C++中混编调用CHEMKIN_第2张图片
成功!

你可能感兴趣的:(计算流体力学,c++,开发语言,fortran)