|
[Sponsors] |
July 30, 2016, 17:10 |
Runtime Type Selection
|
#1 |
Senior Member
Sergei
Join Date: Dec 2009
Posts: 261
Rep Power: 21 |
I am looking into the essentials of runtime type selection mechanism (RTS) deployed in OpenFoam. Take polyPatch class as an example. The .h file:
Code:
//--- polyPatch.H --- class polyPatch { public: //- Runtime type information TypeName("patch"); Code:
static const char* typeName_() { return "patch"; } static const ::Foam::word typeName; virtual const word& type() const { return typeName; } Code:
//--- polyPatch.C --- namespace Foam { defineTypeNameAndDebug(polyPatch, 0); Code:
const ::Foam::word polyPatch::typeName(polyPatch::typeName_()); |
|
August 1, 2016, 18:44 |
|
#2 |
Senior Member
Sergei
Join Date: Dec 2009
Posts: 261
Rep Power: 21 |
Below is the code responsible for runtime type selection (RTS) in class polyPatch. The code which is not relevant to RTS was left out for the sake of clearness.
Code:
//--- polyPatch.H --- class polyPatch { public: //- Runtime type information TypeName("patch"); // Declare run-time constructor selection tables declareRunTimeSelectionTable ( autoPtr, polyPatch, word, ( const word& name, const label size, const label start, const label index, const polyBoundaryMesh& bm, const word& patchType ), (name, size, start, index, bm, patchType) ); // Constructors //- Construct from components polyPatch ( const word& name, const label size, const label start, const label index, const polyBoundaryMesh& bm, const word& patchType ); // Selectors //- Return a pointer to a new patch created on freestore from // components static autoPtr<polyPatch> New ( const word& patchType, const word& name, const label size, const label start, const label index, const polyBoundaryMesh& bm ); Code:
//--- polyPatch.H --- class polyPatch { public: //- Runtime type information static const char* typeName_() { return "patch"; } static const ::Foam::word typeName; // Declare run-time constructor selection tables //- Declare a run-time selection /* Construct from argList function pointer type */ typedef autoPtr<polyPatch> (*wordConstructorPtr) ( const word& name, const label size, const label start, const label index, const polyBoundaryMesh& bm, const word& patchType ); /* Construct from argList function table type */ typedef HashTable<wordConstructorPtr, word, string::hash> wordConstructorTable; /* Construct from argList function pointer table pointer */ static wordConstructorTable* wordConstructorTablePtr_; /* Table constructor called from the table add function */ static void constructwordConstructorTables(); /* Table destructor called from the table add function destructor */ static void destroywordConstructorTables(); /* Class to add constructor from argList to table */ template<class polyPatchType> class addwordConstructorToTable { public: static autoPtr<polyPatch> New ( const word& name, const label size, const label start, const label index, const polyBoundaryMesh& bm, const word& patchType ) { return autoPtr<polyPatch>(new polyPatchType (name, size, start, index, bm, patchType)); } addwordConstructorToTable ( const word& lookup = polyPatchType::typeName ) { constructwordConstructorTables(); if (!wordConstructorTablePtr_->insert(lookup, New)) { std::cerr<< "Duplicate entry " << lookup << " in runtime selection table " << "polyPatch" << std::endl; error::safePrintStack(std::cerr); } } ~addwordConstructorToTable() { destroywordConstructorTables(); } }; Code:
//--- polyPatch.C --- namespace Foam { defineTypeNameAndDebug(polyPatch, 0); defineRunTimeSelectionTable(polyPatch, word); addToRunTimeSelectionTable(polyPatch, polyPatch, word); Code:
//--- polyPatch.C --- namespace Foam { const ::Foam::word polyPatch::typeName(polyPatch::typeName_()); /* Define the constructor function table */ polyPatch::wordpolyPatchConstructorTable* polyPatch::wordConstructorTablePtr_ = NULL /* Table constructor called from the table add function */ void polyPatch::constructwordConstructorTables() { static bool constructed = false; if (!constructed) { constructed = true; polyPatch::wordConstructorTablePtr_ = new polyPatch::wordConstructorTable; } } /* Table destructor called from the table add function destructor */ void polyPatch::destroywordConstructorTables() { if (polyPatch::wordConstructorTablePtr_) { delete polyPatch::wordConstructorTablePtr_; polyPatch::wordConstructorTablePtr_ = NULL; } } /* Add the thisType constructor function to the table */ polyPatch::addwordConstructorToTable<polyPatch> addpolyPatchwordConstructorTopolyPatchTable_ Code:
//--- polyPatchNew.C --- Foam::autoPtr<Foam::polyPatch> Foam::polyPatch::New ( const word& patchType, const word& name, const label size, const label start, const label index, const polyBoundaryMesh& bm ) { wordConstructorTable::iterator cstrIter = wordConstructorTablePtr_->find(patchType); if (cstrIter == wordConstructorTablePtr_->end()) { FatalErrorInFunction << "Unknown polyPatch type " << patchType << " for patch " << name << nl << nl << "Valid polyPatch types are :" << endl << wordConstructorTablePtr_->sortedToc() << exit(FatalError); } return autoPtr<polyPatch> ( cstrIter() ( name, size, start, index, bm, patchType ) ); } Moreover, addpolyPatchwordConstructorTopolyPatchTable_ is a global object which means that it can be visible in every translation unit the library (shared object (.so)) it is built in is linked to. What's the point? All addpolyPatchwordConstructorTopolyPatchTable_ has to do is to be constructed and destroyed, literally it is addressed 2 times throughout the program runs. Declaring it as static polyPatch::addwordConstructorToTable<polyPatch> addpolyPatchwordConstructorTopolyPatchTable_ (or putting it to an unnamed namespace{})can narrow the scope it is visible from to the single translation unit it is defined in. Or even better choice, don't make it global, make it a static member defined in a private section of class polyPatch. Typedefed types wordConstructorPtr and wordConstructorTable should be put in protected section as well (they are used in functions New of base class polyPatch and derived classes). Now let me dissect function constructwordConstructorTables(), replicating its code below Code:
/* Define the constructor function table */ polyPatch::wordpolyPatchConstructorTable* polyPatch::wordConstructorTablePtr_ = NULL /* Table constructor called from the table add function */ void polyPatch::constructwordConstructorTables() { static bool constructed = false; if (!constructed) { constructed = true; polyPatch::wordConstructorTablePtr_ = new polyPatch::wordConstructorTable; } } Code:
void polyPatch::constructwordConstructorTables() { if (!polyPatch::wordConstructorTablePtr_) { polyPatch::wordConstructorTablePtr_ = new polyPatch::wordConstructorTable; } } Last edited by Zeppo; August 2, 2016 at 14:12. |
|
August 2, 2016, 16:58 |
|
#3 | |
Senior Member
Sergei
Join Date: Dec 2009
Posts: 261
Rep Power: 21 |
Here you can find an article on runtime type selection in OpenFoam: http://openfoamwiki.net/index.php/Sn...tion_mechanism
At the very bottom of the page it reads: Quote:
Second, suppose you have Base and Derived in different libraries: Base is built into library libBase.so, and Derived is built into library libDerived.so. And you want to use these libraries in your application, linking them to you app at runtime. The only proper way to do so is when libBase.so is linked dynamically first so that the static hashtable (defined in class Base) is created and initialised. Then you can load (dynamically link) library Derived.so which creates a global object addDerivedTypeMrConstructorToBaseTable_ which in turn puts Derived's "virtual constructor" (a pointer to the static member function actually) into the hashtable. When it comes to OpenFoam, class Base (being an interface class) is integral part of OpenFoam and is built into OpenFoam library (e.g finiteVolume.so or whatever). Implicitly, you make it dynamically linked through your file Make/options. The library libDerived.so can be instructed to be dynamically linked either implicitly in the same file Make/options or explicitly through the call to dlopen and dlsym in the code (controlDict's subdict libs should control it somehow). All this guarantees hashtable is initialised first and then securely filled with "virtual constructors" from derived classes. p.s. Another decent article on the subject can be found here: http://www.sourceflux.de/blog/runtim...tion-openfoam/ |
||
Tags |
rts, runtime type selection |
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Too high omega and k values in vortex flow simulation | thomas. | OpenFOAM Running, Solving & CFD | 9 | March 30, 2016 07:45 |
Boundary Conditions | MtnRunBeachBum | OpenFOAM Pre-Processing | 1 | April 30, 2015 17:33 |
LES supersonic free jet | martyn88 | OpenFOAM | 22 | April 17, 2015 07:00 |
interFoam/kOmegaSST tank filling with printStackError/Mules | simpomann | OpenFOAM Running, Solving & CFD | 3 | February 17, 2014 18:06 |
Problem with compile the setParabolicInlet | ivanyao | OpenFOAM Running, Solving & CFD | 6 | September 5, 2008 21:50 |