CFD Online Discussion Forums

CFD Online Discussion Forums (
-   SU2 (
-   -   Pointers to Objects (

Amirkb May 23, 2019 13:49

Pointers to Objects
Hi all,

I had a question about how objects are passed as function parameters inside SU2. In some cases, objects are created as pointers to their respective classes. An example is the following:


void CDiscAdjSolver::SetSurface_Sensitivity(CGeometry *geometry, CConfig *config) { }
As I understand, in the above code, geometry and config are object pointers that are passed to SetSurface_Sensitivity as inputs, and are later on used inside. The methods within these classes are accessed via the arrow operator. So far so good.

In some function calls however, we get something similar to the following:


void CDiscAdjFluidIteration::InitializeAdjoint(CSolver *****solver_container, CGeometry ****geometry_container, CConfig **config_container, unsigned short iZone, unsigned short iInst){}
I'm having a hard time understanding what the 5 asterisks mean? Does that create 5 nested pointers? Or a 5d array of a pointer to the classes? This gets more confusing when the containers are used inside the methods. For example, in the method above, we have:


solver_container[iZone][iInst][MESH_0][ADJFLOW_SOL]->SetAdj_ObjFunc(geometry_container[iZone][iInst][MESH_0], config_container[iZone]);
I know MESH_0 and ADJFLOW_SOL represent constants which are assigned integer values, but I don't understand what they do to solver_container? For example how is solver_container[1][2][3][4] different to solver_container[1][2][3][0]? What are we accessing here using the integers?

I'm relatively new to C++ so it might be something fundamental that I'm missing here, but I've done a fair bit of digging online and can't seem to find anything similar. If anyone has any clue what the above means I'd be grateful if they could help.


pcg May 23, 2019 17:49

Hi Amir,
One of the dereference operators (*) is for polymorphism (it should be easy to read about this online).
The others are to create an nd-array of which:
1st dimension is for zones defined in the mesh file.
2nd is for instances but I don't think that is in use now.
3rd is for grids (of the same zone) this is used for multigrid acceleration.
4th is for different solvers, numerics, etc. that a zone needs, for example a NS solver and a turbulent solver for RANS simulations, they are stored in fixed (static) locations to make it clear which solver is being accessed, even if the container is never completely full.

The numerics container only has numerics pointers to CNumerics objects, the solver container pointer to CSolver objects, etc.


Amirkb May 24, 2019 12:59

Hi Pedro,

Once again, thanks for your help.

Is there anywhere in the code where the structure of the container arrays are defined? For example, a geometry_container is defined in various functions within the code, sometimes with one asterisk, sometimes two, three or four.

How does one determine what the size of the nd-array for the container has to be? Are these defined/allocated anywhere?

I guess my question stems from the fact that I don't understand what the use of these arrays are? Can't we just always create the objects with only one deference operator?


pcg May 25, 2019 07:26

At the highest level of the hierarchy you have CDriver, all the containers "belong" to the driver, and the driver allocates and populates these containers in corresponding "XX_Preprocessing" methods.
I use belong in "" because these containers are just pointers (addresses in memory), the actual objects live somewhere in memory, but as with most things in programming it is a matter of abstraction, so lets say the containers are... contained (cough)... in the driver.
Now, the driver passes the addresses (pointers) of these objects down to the methods of the classes that make use of them. The important thing is that the objects are only created by the driver, when you see "CSolver *solver" as a function argument this is not a new solver, simply the address of something that exists in memory.
Some methods have as arguments only one pointer to solver because the client for the method will decide for it what solver it should work on. Others get the entire nd-array of pointers because they need to operate on multiple solvers, for example methods related to multigrid need to loop trough all the grids of a given zone and there is a solver associated to each grid (not because they are different solvers, but because they contain different data).

You could argue that this architecture is too flexible, for example if CIteration uses CSolver then maybe it should own the solver, or if CSolver uses CNumerics maybe it should own them instead of driver... And if the code had been written like that I would now probably say the architecture is inflexible...

Anyway, what helped me the most understanding the design intent of each class and how they should interact with each other was to start at the top (CDriver.Run()) and go down the rabbit hole, or in programming terms, follow the call stack.

All times are GMT -4. The time now is 12:30.