实现fortran和c++的耦合编程,主要有两种方式,一种是采用静态链接库,一种是使用动态链接库;
区别是,静态链接库在c++的程序中,可以直接设置断点进行调试,二动态链接库则不行;
下面分别给出两个的代码示例,程序中还调用了sundials库求解常微分方程:
静态链接库方式:
1.fortran代码:
implicit none
interface
subroutine solve_ode() bind(C, name="solve_ode")
end subroutine solve_ode
end interface
call solve_ode()
end program call_cpp_solver
c++ 代码:
#include "pch.h"
// ExampleLib.cpp
#include <iostream>
#include <cvode/cvode.h> // 包含SUNDIALS的CVODE库
#include <nvector/nvector_serial.h> // 用于序列向量操作
#include <sunmatrix/sunmatrix_dense.h> // 密集矩阵操作
#include <sunlinsol/sunlinsol_dense.h> // 密集线性求解器
#include <cvode/cvode_direct.h> // CVODE直接方法求解器
#include <sundials/sundials_types.h> // 定义SUNDIALS的类型
// 简单的微分方程函数 dy/dt = -ky
static int f(realtype t, N_Vector y, N_Vector ydot, void* user_data) {
realtype k = *(realtype*)user_data;
NV_Ith_S(ydot, 0) = -k * NV_Ith_S(y, 0);
return 0;
}
extern "C" {
void solve_ode() {
SUNContext sunctx;
SUNContext_Create(NULL, &sunctx);
realtype t0 = 0.0, t = 1.0, dt = 0.1, k = 0.1;
N_Vector y = N_VNew_Serial(1, sunctx);
NV_Ith_S(y, 0) = 1.0; // 初始条件
void* cvode_mem = CVodeCreate(CV_ADAMS, sunctx);
CVodeInit(cvode_mem, f, t0, y);
CVodeSStolerances(cvode_mem, 1e-4, 1e-4);
CVodeSetUserData(cvode_mem, &k);
SUNMatrix A = SUNDenseMatrix(1, 1, sunctx);
SUNLinearSolver LS = SUNLinSol_Dense(y, A, sunctx);
CVodeSetLinearSolver(cvode_mem, LS, A);
while (t < 10) {
CVode(cvode_mem, t, y, &t, CV_NORMAL);
std::cout << "At t = " << t << ", y = " << NV_Ith_S(y, 0) << std::endl;
t += dt;
}
// 清理
N_VDestroy(y);
CVodeFree(&cvode_mem);
SUNMatDestroy(A);
SUNLinSolFree(LS);
}
}
2. 动态链接库方式
fortran 代码:
program call_cpp_dll
implicit none
interface
subroutine solve_ode() bind(C, name="solve_ode")
end subroutine solve_ode
end interface
call solve_ode()
end program call_cpp_dll
c++代码:
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <iostream>
#include <cvode/cvode.h> // 包含SUNDIALS的CVODE库
#include <nvector/nvector_serial.h> // 用于序列向量操作
#include <sunmatrix/sunmatrix_dense.h> // 密集矩阵操作
#include <sunlinsol/sunlinsol_dense.h> // 密集线性求解器
#include <cvode/cvode_direct.h> // CVODE直接方法求解器
#include <sundials/sundials_types.h> // 定义SUNDIALS的类型
//BOOL APIENTRY DllMain( HMODULE hModule,
// DWORD ul_reason_for_call,
// LPVOID lpReserved
// )
//{
// switch (ul_reason_for_call)
// {
// case DLL_PROCESS_ATTACH:
// case DLL_THREAD_ATTACH:
// case DLL_THREAD_DETACH:
// case DLL_PROCESS_DETACH:
// break;
// }
// return TRUE;
//}
// ExampleLib.cpp
#include <iostream>
// 确保正确地定义导出和导入宏
#ifdef EXAMPLELIB_EXPORTS
#define EXAMPLELIB_API __declspec(dllexport)
#else
#define EXAMPLELIB_API __declspec(dllimport)
#endif
extern "C" {
EXAMPLELIB_API void solve_ode();
}
// 简单的微分方程函数 dy/dt = -ky
static int f(realtype t, N_Vector y, N_Vector ydot, void* user_data) {
realtype k = *(realtype*)user_data;
NV_Ith_S(ydot, 0) = -k * NV_Ith_S(y, 0);
return 0;
}
void solve_ode() {
SUNContext sunctx;
SUNContext_Create(NULL, &sunctx);
realtype t0 = 0.0, t = 1.0, dt = 0.1, k = 0.1;
N_Vector y = N_VNew_Serial(1, sunctx);
NV_Ith_S(y, 0) = 1.0; // 初始条件
void* cvode_mem = CVodeCreate(CV_ADAMS, sunctx);
CVodeInit(cvode_mem, f, t0, y);
CVodeSStolerances(cvode_mem, 1e-4, 1e-4);
CVodeSetUserData(cvode_mem, &k);
SUNMatrix A = SUNDenseMatrix(1, 1, sunctx);
SUNLinearSolver LS = SUNLinSol_Dense(y, A, sunctx);
CVodeSetLinearSolver(cvode_mem, LS, A);
while (t < 10) {
CVode(cvode_mem, t, y, &t, CV_NORMAL);
std::cout << "At t = " << t << ", y = " << NV_Ith_S(y, 0) << std::endl;
t += dt;
}
// 清理
N_VDestroy(y);
CVodeFree(&cvode_mem);
SUNMatDestroy(A);
SUNLinSolFree(LS);
}