How to Access DataBase
Accessing to the database is one of the most frequent operations in a Finite Element context.
In a Finite Element context we often need to store information on the Nodes and on the Elements. This data may take different forms (scalars, vectors, matrices ... ) and needs to be widely accessible inside a finite element program. In the Kratos, this data is stored direcly in the objecect from which it will be accessed, meaning that the nodes will contain the nodal data, and the elements the elemental data.
The Kratos provides both a nodal and elemental "Variable Database", which allows to store in a flexible way VARIABLES of different type. A detailed description of the design concepts together with a study of the perfomance issues can be found in Pooyan's Thesis. The aim of current "How To" is just to provide a brief introduction on the usage of the cpp interface.
Contents |
Nodal Database
The "Nodes" constitute one of the building blocks of the Kratos interface and provide the richest database structure. Conceptually each nodes allocates a portion of memory sufficient to contain a database with all of its data. In the practice the memory needed is defined by the user which at the beginning of the program has to select and add to the model part the list of variables that will be needed during the analysis.
As a concept we should also note that for some variables a "history" (the value of this variables in the past steps) will be needed, while for others only the current value will be necessary. In order to make this possible the Kratos provides two different implementations for the "Historical Database" and for the "Non-Historical one".
The two databases are independent from each other and are not syncronized
Historical Database
The "Historical Database" stores the present value of a variable and the value it took in the previews steps. The Number of steps stored depends on the size of "Buffer". This can be modified by the function "SetBufferSize" while the present value can be obtained by "GetBufferSize()"
to make an example
model_part.SetBufferSize(3) unsigned int model_part.GetBufferSize(); ##now outputs 3
implies storing the current step + the 2 last steps.
The list of the variables to be stored and the buffer size needs to be known in order to use the Historical Database. This is obtained by providing at the beginning of the analysis the list of all the variables that will be involved in the calculation. to make an example if a given solver will need the variables TEMPERATURE and VELOCITY, the user should provide before creating the list of nodes the two commands
model_part.AddNodalSolutionStepVariable(TEMPERATURE) model_part.AddNodalSolutionStepVariable(VELOCITY)
In the practice each solver provides the list of its variables through the function AddVariables(...) (examples of this can be found in any of the "test examples"). Note that trying to access for example to PRESSURE will lead to an error as the database did not allocate any memory to hold the variable PRESSURE
Once this preliminary operations are performed, the memory for the Kratos is allocated and can be used efficiently. Two Functions Exist to access to the solution step data:
- GetSolutionStepData
- FastGetSolutionStepData
their functionality is identical but they differ in the checks that are performed internally in the RELEASE version (They are identical in DEBUG). The "Fast" operator, does not perform any check, meaning that if, in the example before, we try to access to PRESSURE (not in the variable list) we will get a segmentation fault without any further information.
The syntax is as follows:
Node<3>::iterator inode = model_part.NodesBegin(); //to make example let's take the first node //here we get REFERENCES to the database!! array_1d<double,3>& vel = inode->FastGetSolutionStepValue(VELOCITY); //vel here has the value of velocity at the current step const array_1d<double,3>& oldvel = inode->FastGetSolutionStepValue(VELOCITY,1); //vel 1 step in the past const array_1d<double,3>& veryoldvel = inode->FastGetSolutionStepValue(VELOCITY,2); //vel 2 steps in the past // //predicting the vel as vel = 2*oldvel - veryoldvel; noalias(vel) = 2.0 * oldvel; noalias(vel) -= veryoldvel; //NOTE: "vel" is a REFERENCE to the database => changing "vel" we change the database
Non-Historical Database
On the side of the "historical" database it is also possible to store variables which do not change as the time step evolves. As an important difference with respect to the historical database, the list of variables included nor the "size" of the objects does not need to be prescribed at the beginning of the program and can be changed dynamically during the run.
ANY element type can be included in this sort of database. As an example, a part for the standard types double array_1d<double,3> Matrix we can use user defined types. Two useful examples of this are
- NEIGHBOUR_NODES
- NEIGHBOUR_ELEMENTS
The usage of such entities is described elsewhere (..) the important point is here that an array of pointers can be stored without any problems together with the standard datatypes. The implementation details and the discussion of the implementation can be found in Pooyan's Thesis.
The access is through the functions "GetValue()" and "SetValue". To make an example
double temperature = inode->GetValue(TEMPERATURE)
or
double aaa = 10.0 inode->SetValue(TEMPERATURE,aaa);
Elemental Database
The Elemental database is identical to the "non-historical" database (it shares exactly the same implementation). No historical database is implemented for elements and conditions.
The user should nevertheless note that the user can implement a user-defined storage through the elemental interface (see for example the function Calculate or CalculateOnIntegrationPoints)