- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I need to call a DLL coded in C++ from my Fortran. The methods I need to call are object-oriented, and described in .h files. Here is the first 50 or so lines from one of the .h files:
[cpp]
#ifndef BBE_PVTT_BLACK_OIL_FLUID_H
#define BBE_PVTT_BLACK_OIL_FLUID_H
#include <PVTT/API/Model/Dll.h>
#include <PVTT/API/Common/PVTTEnum.h>
#include <PVTT/API/Common/PVTTBlackOilEnum.h>
#include <PVTT/API/Common/BlackOilImpurities.h>
#include <PVTT/API/Common/BlackOilComposition.h>
#include <string>
namespace BBE { namespace PVTT { namespace Common {
class ErrorReport;
} } }
namespace BBE { namespace PVTT { namespace Impl { namespace Command {
class BlackOilFluidCommand;
} } } }
namespace BBE { namespace PVTT { namespace Model {
class BBE_PVTT_API_MODEL_DECL BlackOilFluid
{
public:
BlackOilFluid(const std::string& name="");
BlackOilFluid(const BlackOilFluid&);
BlackOilFluid& operator=(const BlackOilFluid&);
~BlackOilFluid();
bool operator==(const BlackOilFluid&) const;
bool operator!=(const BlackOilFluid&) const;
std::string GetName() const;
void SetName(const std::string& name);
// Set properties
void SetOilAPI(double OilAPI); // setting oil API sets oil specific gravity and vice versa
void SetOilSpecificGravity(double OilSpecificGravity);
void SetGasSpecificGravity(double value, BBE::PVTT::Common::pvtEnumGasSpecGravCondition conditions= BBE::PVTT::Common::pvtCONDITION_STD);
void SetSeparatorConditions(double separatorPressure, double separatorTemperature);
void SetWaterSpecificGravity(double waterSpecificGravity);
void SetWaterSalinity(double weightPercent);
void SetImpurities(const BBE::PVTT::Common::BlackOilImpurities& impurities);
void SetGasComposition(const BBE::PVTT::Common::BlackOilComposition& composition);
void SetGasPpcTpc(double Ppc, double Tpc);
void SetStockTankRelativeVolumes( double gas, double oil, double water );
void SetDeadOilViscosityCoefficientA( double coeffA );
void SetDeadOilViscosityCoefficientB( double coeffB );
void SetGasSpecificHeatCapacity( double gasCp );
void SetOilSpecificHeatCapacity( double oilCp );
void SetWaterSpecificHeatCapacity( double waterCp );
void SetGasThermalConductivity( double gasTc );
void SetOilThermalConductivity( double oilTc );
void SetWaterThermalConductivity( double waterTc );
void SetSpecificLatentHeatOfVaporization( double specificLatentHeatOfVaporization );
[/cpp]
Ideally, I would like to wind up with Object-oriented Fortran code, where a call to one of the above methods uses standard Fortran 2003 syntax, somethig like
[fortran]
call fluid%SetOilApi(35.0d0)
call fluid%SetSeparatorConditions(1d6,320d0)
[/fortran]
To make this happen, I realize I need to create a Fortran INTERFACE definition to describe all the methods I need to call. But I have no real idea what this would look like ... or even if it is possible at all. Any pointers and/or advice to get me started, please?
Qolin
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You won't be able to call the C++ methods directly, as the Fortran ISO_C_Binding module only directly supports interfacing to C. However, you can probably write some interface functions in plain C that will enable you to create the C++ objects and then interact with them.
In your specific example, there is a further hurdle to overcome with the presence of a std::string reference in your constructor. I can't think of any way of simulating a std::string reference (or indeed any sort of reference) within Fortran, so you may at the very least need to use a char* rather than a std:;string for the object name. For a more general example, in what follows I'm going to ignore the constructor arguments altogether. Then you can define a couple of C functions along the lines of:
[cpp] extern "C" void * createFluidObject() { BlackOilFluid *fluid = new BlackOilFluid(); return static_cast<void *>(fluid); } extern "C" void setOilApi(void * fluidObject, double OilApi) { BlackOilFluid *fluid = static_cast<BlackOilFluid *>(fluidObject); fluid -> SetOilAPI(OilApi); }
[/cpp]
with Fortran interfaces of the form:
[fortran] interface function createFluidObject() bind(c, name='createFluidObject') use, intrisic :: iso_c_binding type(c_ptr) :: createFluidObject end function createFluidObject end interface interface subroutine setOilApi(fluid, OilApi) bind(c, name='setOilApi') use, intrisic :: iso_c_binding type(c_ptr), value :: fluid kind(real(1d0)), value :: OilApi end subroutine setOilApi end interface
[/fortran]
...and then, when you want to instantiate your 'fluid' object and interact with it you can write your Fortran code like this:
[fortran] fluid = createFluidObject() call setOilApi(fluid, OilApi)
[/fortran]
...and so on.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Eos, that's exactly what I need. I have made a start on creating the vanilla C interface, and so far it seems straightforward. I'll leave the constructor fluid name til later.
Cheers!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
qolin,
Apparently you are creating the objects on the C++ side. So you could write the Fortran shell functions to pass CHARACTER*(*) for passing name (or other variable length arguments).
Jim Dempsey

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page