How to use the DataStorage

This recipe is incomplete and out-of-date and needs to be adapted

Purpose

This recipe assumes you have completed sucessfully the SelfConfigurationRecipe.

The purpose of this recipe is to show the use of the following features of the COOLFluiD framework:

At the end of this recipe you should be able to understand how data is stored in the DataStorage both for easier parallelization and for sharing between different parts of the program.


!!Step 1!! Go to the "Recipes" directory. Go into the "Recipe03" directory. Edit the file "main.cxx". The code present here is the result of the work already done in recipes SelfRegistrationRecipe and SelfConfigurationRecipe.

You may notice that the class ProgramConfig has been moved to a header file, ProgramConfig.hh.

To start this recipe, first create a file ProgramData.hh and implement the following code there:

[<html>] <SPAN style="color:#333333;background-color:#cccccc;font-size:10px;border: 1px solid gray;padding:5px 5px 5px 5px;white-space: pre; display:block;"> <pre> #ifndef ProgramData_hh #define ProgramData_hh

#include "Framework/MeshData.hh"

class ProgramData : public COOLFluiD::Framework::ConfigObject { public:

ProgramData() : COOLFluiD::Framework::ConfigObject("Data"), _meshData() {

_nbGeoEnts = 0; addConfigOption("nbGeoEnts",

"Description of this parameter goes here.", &_nbGeoEnts);

}

void configure(const COOLFluiD::Framework::ArgMap& args) {

using namespace COOLFluiD; using namespace COOLFluiD::Framework;

ConfigObject::configure(args);

const CFluint nbStates = _nbGeoEnts * 3; const CFluint nbNodes = _nbGeoEnts * 3;

_meshData.getLocalData()->createData&#60State*&#62("states", nbStates); _meshData.getLocalData()->createData&#60Node*&#62("nodes", nbNodes);

}

~ProgramData() {

using namespace COOLFluiD; using namespace COOLFluiD::Framework;

DataHandle<LOCAL,State*> states =

_meshData.getLocalData()->getData&#60State*&#62("states");

DataHandle<LOCAL,Node*> nodes =

_meshData.getLocalData()->getData&#60Node*&#62("nodes");

for(CFluint i =0; i < states.size(); ++i) {

deletePtr(states[i]);

} for(CFluint i =0; i < nodes.size(); ++i) {

deletePtr(nodes[i]);

}

}

void getData(vector<COOLFluiD::Framework::State*>& geoStates,

vector<COOLFluiD::Framework::Node*>& geoNodes, const COOLFluiD::CFluint& geo)

{

using namespace COOLFluiD; using namespace COOLFluiD::Framework;

DataHandle<LOCAL,State*> states =

_meshData.getLocalData()->getData&#60State*&#62("states");

DataHandle<LOCAL,Node*> nodes =

_meshData.getLocalData()->getData&#60Node*&#62("nodes");

geoStates[0] = states[geo*3 + 0]; geoStates[1] = states[geo*3 + 1]; geoStates[2] = states[geo*3 + 2];

geoNodes[0] = nodes[geo*3 + 0]; geoNodes[1] = nodes[geo*3 + 1]; geoNodes[2] = nodes[geo*3 + 2];

}

void createData() {

using namespace COOLFluiD; using namespace COOLFluiD::Framework;

const CFbool onMesh = true;

DataHandle<LOCAL,State*> states =

_meshData.getLocalData()->getData&#60State*&#62("states");

DataHandle<LOCAL,Node*> nodes =

_meshData.getLocalData()->getData&#60Node*&#62("nodes");

for(CFluint i =0; i < states.size(); ++i) {

nodes[i] = new Node(onMesh); states[i] = new State(); states[i]->setSpaceCoordinates(nodes[i]);

}

}

void createData() {

using namespace COOLFluiD; using namespace COOLFluiD::Framework;

const CFbool onMesh = true;

DataHandle<LOCAL,State*> states =

_meshData.getLocalData()->getData&#60State*&#62("states");

DataHandle<LOCAL,Node*> nodes =

_meshData.getLocalData()->getData&#60Node*&#62("nodes");

for(CFluint i =0; i < states.size(); ++i) {

nodes[i] = new Node(onMesh); states[i] = new State(); states[i]->setSpaceCoordinates(nodes[i]);

}

CFLog(INFO,"Created " << states.size() << " states and nodes." << std::endl);

}

COOLFluiD::CFluint getNbGeoEnts() const {

return _nbGeoEnts;

}

private:

COOLFluiD::Framework::MeshData _meshData;

COOLFluiD::CFluint _nbGeoEnts;

}; // end class ProgramData

#endif // ProgramData_hh </pre> </span> [</html>]

This class makes use of the MeshData class to access the DataStorage. In the constructor it defines a parameter for configuration, which is an integer with the number of GeometricEntity's to create. It also implemets the configure() class by extending the parent configure(), where it uses the parameter that has just been configured to create the data inside DataStorage with the correct size.

Notice the call to createData() in the end of the configure() method. Its the proper way to do it, giving a name to the data, and specifying the data type as the template parameter.

In the destructor, the data is fetched to destroy any dynamic allocated data held by the pointers in "states" and in "nodes". Notice that the name of the data is also used for the identifier of the DataHandle<>. Although not mandatory, always prefer this nomenclature to avoid confusion. Notice also the data is being destroyed by the deletePtr() function, that takes care of checking if the object actually exists or not and setting the pointer back to CFNULL after the deletion.

The function getData() is used to put the pointers to states and nodes of a certain GeometricEntity in the placeholders to pass to the constructor of the GeometricEntity.

The function createData() allocates the dynamic memory for nodes and states. Notice again the fetching of the data, already created. If the data had not been created an exception would be thrown.


!!Step 2!!

Now, we are going to incorporate this new object into the program. First include the header file in the main.cxx():

[<html>] <SPAN style="color:#333333;background-color:#cccccc;font-size:10px;border: 1px solid gray;padding:5px 5px 5px 5px;white-space: pre; display:block;"> <pre> ... #include "ProgramConfig.hh" #include "ProgramData.hh"

using namespace std; ... </pre> </span> [</html>]

Then we take care of building an object of the type ProgramData and configuring it, but now we'll make use of another function, configureNested() which allows an object to configure another with his name, nested around it.

[<html>] <SPAN style="color:#333333;background-color:#cccccc;font-size:10px;border: 1px solid gray;padding:5px 5px 5px 5px;white-space: pre; display:block;"> ...

try {

ProgramData pdata;

ProgramConfig cfg;

cfg.setConfigFile("Config.txt");

cfg.configure(); cfg.configureNested(&pdata);

PhysicalModel::setPhysicalModelImpl(cfg.getPhysicalModelName());

... </span> [</html>]


!!Step 3!!

You'll also need to substitute the part of building the GeometricEntity, in order to use the data stored in the ProgramData, which by itself makes use of the DataStorageFacility.

[<html>] <SPAN style="color:#333333;background-color:#cccccc;font-size:10px;border: 1px solid gray;padding:5px 5px 5px 5px;white-space: pre; display:block;"> ...

BaseGeometricEntityProvider&#60Cell&#62* cellProvider =

GeometricEntityFactory&#60Cell&#62::getProvider(cfg.getGeometricEntityName());

pdata.createData();

const CFluint nbStatesInCell = 3; const CFluint nbNodesInCell = 3;

vector&#60State*&#62 statesInCell(nbStatesInCell); vector&#60Node*&#62 nodesInCell(nbNodesInCell);

for (CFluint i = 0; i < pdata.getNbGeoEnts(); ++i) {

pdata.getData(statesInCell,nodesInCell,i);

GeometricEntity * cell = cellProvider->create(statesInCell,nodesInCell);

CFLog(INFO,"Created GeometricEntity " << i << std::endl);

deletePtr(cell);

}

} catch (exception& e) {

... </span> [</html>]


!!Step 4!!

You can now try to compile. This code should compile without errors or warnings. If you run it, the out put should be:

[<html>] <SPAN style="color:#000000;background-color:#FFFFCC;font-size:10px;border: 1px solid gray;padding:5px 5px 5px 5px;white-space: pre; display:block;"> prompt:Recipe03> ./program COOLFluiD Recipe 3 starting: Configuring: ProgConfig Configuring: Data Set PhysicalModel to: Euler2D Created 0 states and nodes. </span> [</html>]

Something did not happen as we wanted. No states and notes were created. Neither GeometricEntity's. Ah! This is because we forgot to configure the program with the number of GeometricEntity's we want to build.

Edit the file Config.txt, and add the last line:

[<html>] <SPAN style="color:#333333;background-color:#cccccc;font-size:10px;border: 1px solid gray;padding:5px 5px 5px 5px;white-space: pre; display:block;"> ProgConfig.PhysicalModel = Euler2D ProgConfig.GeoEnt = LagrangeTriagP1P1 ProgConfig.Data.nbGeoEnts = 10 </span> [</html>]

Notice the nesting of the name of the second object "Data" inside the first object "ProgConfig", finilized with the parameter and its assignement. The best way to think of it is in terms of a hierarchy of objects.

Save the file and run the program again. No need to recompile! Isn't it COOL!? The output should be:

[<html>] <SPAN style="color:#000000;background-color:#FFFFCC;font-size:10px;border: 1px solid gray;padding:5px 5px 5px 5px;white-space: pre; display:block;"> prompt:Recipe03> ./program COOLFluiD Recipe 3 starting: Configuring: ProgConfig Configuring: Data Set PhysicalModel to: Euler2D Created 30 states and nodes. Created GeometricEntity 0 Created GeometricEntity 1 Created GeometricEntity 2 Created GeometricEntity 3 Created GeometricEntity 4 Created GeometricEntity 5 Created GeometricEntity 6 Created GeometricEntity 7 Created GeometricEntity 8 Created GeometricEntity 9 </span> [</html>]

Congratulations!! You're done with this recipe'''


!!!See also!!! This recipe continues in the NumericalIntegrationRecipe.