填周六的坑,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++中的库时,会出现这样的报错
原因可以参考这个博客
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);
}
其中IData
和FData
即为数组。
我们当前要调用的是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.cpp
和GetVis.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 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);
}
//GetVis.cpp
#include
#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;
}