CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   OpenFOAM Programming & Development (https://www.cfd-online.com/Forums/openfoam-programming-development/)
-   -   Run time Selection Mechanism - Some help required to understand (https://www.cfd-online.com/Forums/openfoam-programming-development/62905-run-time-selection-mechanism-some-help-required-understand.html)

jaswi March 23, 2009 13:39

Run time Selection Mechanism - Some help required to understand
 
Dear Forum Users

Good Evening to all

Run Time Selection Mechanism is one of the wonderful features of OpenFOAM. Understanding how it works is a bit involved. I have tried to look into its implementation but need some help from experts. I hope I will be able to get some answers.

Lets start :-)

Certain Macros constitute the core of this implementation, namely:
  1. declareRunTimeSelectionTable
  2. defineRunTimeSelectionTable
  3. addToRunTimeSelectionTable
Classes which use this mechanism invoke:

  • the macro declareRunTimeSelectionTable in their header file
  • the other two macros in their cpp file.
For further discussion , I have used the class polyPatch. If we take a look at its header file, we find it has 2 definitions for run time selection tables. They read:

Code:

// 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
            ),
            (name, size, start, index, bm)
        );
 

        declareRunTimeSelectionTable
        (
            autoPtr,
            polyPatch,
            dictionary,
            (
                const word& name, const dictionary& dict,
                const label index,  const polyBoundaryMesh& bm
            ),
            (name, dict, index, bm)
        );

The cpp file - polyPatch.C invoke the other two macros in this way:

Macros when invoked lead to a simple string substitution and then it actually compiles. Listing just the macros will not add to the clarity of what it is doing so I have used the first definition of the selection table to rewrite what these macros are doing exactly.


macro - declareRunTimeSelectionTable:

The first macro reads (Note: syntax correctness requires forward slashes as macros cannot have line breaks) :

Code:

#define declareRunTimeSelectionTable\
(autoPtr,baseType,argNames,argList,parList)                                       

/* Construct from argList function pointer type */                               
    typedef autoPtr<baseType> (*argNames##ConstructorPtr)argList;     
                                                                                                         
    /* Construct from argList function table type */                                   
    typedef HashTable<argNames##ConstructorPtr, word, string::hash>   
        argNames##ConstructorTable;                                   
                                                                       
    /* Construct from argList function pointer table pointer */                         
    static argNames##ConstructorTable* argNames##ConstructorTablePtr_;
    /* Class to add constructor from argList to table */             
    template<class baseType##Type>                                     
    class add##argNames##ConstructorToTable                           
    {                                                                 
    public:                                                           
                                                                       
        static autoPtr<baseType> New argList                           
        {                                                             
            return autoPtr<baseType>(new baseType##Type parList);     
        }                                                             
                                                                       
        add##argNames##ConstructorToTable                             
        (                                                             
            const word& lookup = baseType##Type::typeName             
        )                                                             
        {                                                             
            construct##argNames##ConstructorTables();                 
            argNames##ConstructorTablePtr_->insert(lookup, New);     
        }                                                             
                                                                     
        ~add##argNames##ConstructorToTable()                           
        {                                                             
            destroy##argNames##ConstructorTables();                   
        }                                                             
    };                                                               
                                                                       
    /* Table Constructor called from the table add function */         
    static void construct##argNames##ConstructorTables();           
    /* Table destructor called from the table add function destructor */
    static void destroy##argNames##ConstructorTables()

This macro has five arguments:
  1. autoPtr - name of the pointer. In OpenFOAM its always the smart pointer autoPtr<Type > templated over the type
  2. baseType - Name of the base class
  3. argNames – Not sure what it means exactly
  4. argList - list of arguments
  5. parList - parameter list
Lets compare it with the invocation of this macro for polyPatch.
Code:

    declareRunTimeSelectionTable
        (
          autoPtr –  autoPtr
          baseclass - polyPatch
          argNames – word
          argList - (const word& name, 
                        const label size,   
                        const label start, 
                        const label index,
                        const polyBoundaryMesh& bm),
          parList -  (name, size, start, index,bm)
        );

As a result invocation of this macro we will have the following code :
// it first defines a typedef for the construction of a function pointer type from argList.
Code:

  typedef autoPtr<polyPatch> (* wordConstructorPtr)  ( const word& name, 
                                                                                const label size,   
                                                                                const label start, 
                                                                                const label index,
                                                                                const polyBoundaryMesh& bm
                                                                              );

// Next a typedef is defined for the HashTable, given the argList. It reads:
Code:

typedef HashTable < wordConstructorPtr,  word,  string::hash>  wordConstructorTable;
//it declares a static pointer to the constructor table.
Code:

static wordConstructorTable* wordConstructorTablePtr_;
// the template class reads :
Code:


 template<class polyPatchType>                                                               
    class addwordConstructorToTable                                                 
    {                                                                                                                     
    public:   
      // static function
 
          static autoPtr<polyPatch> New  ( const word& name, 
                                                          const label size,   
                                                          const label start, 
                                                          const label index,
                                                          const polyBoundaryMesh& bm
                                                          )                                                     
            { 
                  return autoPtr<polyPatch> (new polyPatch (name, size, start, index, bm));              }
 
  // constructor
    addwordConstructorToTable ( const word& lookup = polyPatchType::typeName )
    {                                                                                                             
        constructwordConstructorTables();                                     
        wordConstructorTablePtr_->insert(lookup, New);               
  }                                                                                                             
                                 
 // destructor                                                                                       
  ~addwordConstructorToTable()                                             
    {                                                                                                               
        destroywordConstructorTables();                                       
    }
};

Next these two static functions are declared. These two functions are used inside the template class. I am not sure about this but it seems that within a macro the order is not important. These two definitions could have been in the begining as well.
Code:

static void constructwordConstructorTables();
static void destroywordConstructorTables();


macro - defineRunTimeSelectionTable( )

Macro defineRunTimeSelectionTable(baseType, argNames) already expanded for the class polyPatch reads :
Code:

  #define defineRunTimeSelectionTable( polyPatch, word )           

    defineRunTimeSelectionTablePtr(polyPatch, word );
    defineRunTimeSelectionTableConstructor(polyPatch, word)
    defineRunTimeSelectionTableDestructor(polyPatch,word)

The invocation of this macro , further invokes three macros , namely:
defineRunTimeSelectionTablePtr(polyPatch, word);

Code:

#define defineRunTimeSelectionTablePtr(polyPatch, word)               
                                                                         
/* Define the constructor function table and initialized to NULL */
polyPatch::wordConstructorTable*  polyPatch::wordConstructorTablePtr_ = NULL

defineRunTimeSelectionTableConstructor(polyPatch, word)
Code:

#define defineRunTimeSelectionTableConstructor(polyPatch, word)     
/* Table Constructor called from the table add function
void polyPatch :: constructwordConstructorTables()             
    {                                                                 
          static bool constructed = false;                               
          if (!constructed)                                               
                          {                                                             
                            polyPatch::wordConstructorTablePtr_                   
                            = new polyPatch::wordConstructorTable;             
                          constructed = true;                                         
                          }                                                             
                  }

defineRunTimeSelectionTableDestructor(polyPatch, word)
Code:

#define defineRunTimeSelectionTableDestructor(polyPatch, word)       
                                                                         
/* Table destructor called from the table add function destructor */
    void polyPatch::destroywordConstructorTables()               
    {                                                                 
          if (polyPatch::wordConstructorTablePtr_)                   
          {                                                               
              delete polyPatch::wordConstructorTablePtr_;           
              polyPatch::wordConstructorTablePtr_ = NULL;           
                      }                                                               
              }

The first among three macros declares a pointer to the hashtable and initializes it to NULL . The 2nd and 3rd macros implement the static functions, defined in the template class addwordConstructorToTable .


macro - addToRunTimeSelectionTable( ) -
this macro is pretty simple . it reads
Code:

#define addToRunTimeSelectionTable(baseType,thisType,argNames)             
                                                                             
 /* Add the thisType constructor function to the table */                 
  baseType::add##argNames##ConstructorToTable<thisType>                   
  add##thisType##argNames##ConstructorTo##baseType##Table_

When invoked like this for polyPatch : addToRunTimeSelectionTable(polyPatch, polyPatch, word). it will read :
Code:

    polyPatch::addwordConstructorToTable<polyPatch>                 
      addpolyPatchwordConstructorTopolyPatchTable_


Now the questions :-))
1) How / where is the constructor
addwordConstructorToTable is called to construct the table . If the code
Code:

    polyPatch::addwordConstructorToTable<polyPatch>                 
      addpolyPatchwordConstructorTopolyPatchTable_

corresponds to the call to constructor for this template class (which i doubt that it is ) then what about the ctor argument (const word& lookup = polyPatchType::typeName).

Now If I am wrong in asking the first question and we assume that ctor is indeed called then the static function call - constructwordConstructorTables() will create a new HashTable and return a pointer to it. The next statement
Code:

wordConstructorTablePtr_->insert(lookup, New);
inserts an entry into the HashTable based on the value returned by the lookup and the call to the static function New.

2) As I understand from the second code statement in the ctor body, a key is inserted into the HashTable corresponding to the base class. How are the other types of patches entered into this table.

3) Finally what troubles me most is that I am unable to grasp when / where are these tables created during the creational process of fvMesh.

Thanks a lot for your attention.

Best Regards
Jaswi

sharonyue August 26, 2013 22:28

Very Neat!! But Really tough tough for a newbie though...

bieshuxuhe April 18, 2014 07:44

hi,
maybe macro - addToRunTimeSelectionTable( )
Code:

#define addToRunTimeSelectionTable(baseType,thisType,argNames)             
                                                                             
 /* Add the thisType constructor function to the table */                 
  baseType::add##argNames##ConstructorToTable<thisType>                   
  add##thisType##argNames##ConstructorTo##baseType##Table_

for polyPatch should be
Code:

polyPatch::addwordConstructorToTable<thisType>                 
      addthisTypewordConstructorTopolyPatchTable_

The thread is so good for us newcomer to learn runtimeselection Mechanism ! thanks a lot !

bkassar October 29, 2015 13:42

Hi all,
While trying to understand runTimeSelection mechanism, I bumped into this thread and found it very interesting. Maybe this link will help future readers: https://openfoamwiki.net/index.php/O...tion_mechanism


All times are GMT -4. The time now is 05:02.