Update Code Architecture and Organization authored by Alain O' Miniussi's avatar Alain O' Miniussi
## Global view
The main purpose of a fargo3D simulation is to track the evolution of a planetary system embedded in a disk of gas. Those two entities will be represented by a **GasDisk** and **PlanetarySystem** class respectively. A single simulation will instantiate one object of each.
That simulation is driven by an instance of the **SimulationDriver** class (currently implementing a simple [Command pattern](https://en.wikipedia.org/wiki/Command_pattern), but might evolve into a [Template Method](https://en.wikipedia.org/wiki/Template_method_pattern). It behave like a function object with perform one step of the simulation at each call.
The simulation configuration is done through a property tree.
The main sequence diagram can be seen as follow:
```plantuml
participant main
participant driver
participant gasDisk
participant planets
database storage
main -> gasDisk : load initial state
main -> driver : create
loop monitor
loop time steps
main -> driver : next step
driver -> gasDisk : sub step 1
driver -> gasDisk : sub step <N>
gasDisk -> planets : rotate
driver -> main : done
end
main -> gasDisk : write state
gasDisk -> storage : dump fields
main -> planets : monitor
planets -> storage : write position and masses
main -> storage : write disk info
end
```
The (incomplete) class diagram[^1] could be summarized as:
```plantuml
namespace fargOCA {
class SystemPhysic <<(S,#FF7700)>> {
}
class DiskDesc << (S,#FF7700) >> {
}
class DiskPhysic <<S,#FF7700)>> {
}
class DiskGrid << (S,#FF7700) >> {
int nbRadius, nbLayer, nbSector
real minRadius, maxRadius
mpi::communicator comm
}
class PolarGrid {
string name
real[] field
}
class Planet {
sting name
real mass
real x,y,z
real vx,vy,vz
}
class PlanetarySystem {
void rotate(real dt)
void monitor(fileName)
}
class GasDisk {
void applyBoundariesConditions()
void setGhosts()
void read(fileName)
void write(fileName)
void monitor(fileName)
}
class GasDisk::Velocity {
}
class SimuProgress {
real physicalTime
real step
void isOutputStep()
}
class BoundariesHandler {
string name
void operator()(GarsDisk& gas, real step);
}
class FctBoundariesHandler {
void operator()(GarsDisk& gas, real step);
}
FctBoundariesHandler --|> BoundariesHandler
GasDisk o--> "many" BoundariesHandler
}
namespace D3 {
class SimulationDriver {
void operator()(flow, torque)
-- private sub steps ---
void subStep1(..)
void subStep<N>(..)
-- private util. --
myRadiationManager
myTransport
}
}
note top of fargOCA.DiskPhysic
Configuration of the disk
physical properties
and behavior
end note
note left of fargOCA.SystemPhysic
Configuration of the
planetary system
physical properties
and behavior
end note
D3.SimulationDriver o--> fargOCA.GasDisk
D3.SimulationDriver o--> fargOCA.SimuProgress
fargOCA.PlanetarySystem "1"*-->"many" fargOCA.Planet
fargOCA.PlanetarySystem o--> fargOCA.SystemPhysic
fargOCA.DiskDesc "1"*-->"1" fargOCA.DiskGrid
fargOCA.DiskDesc "1"*-->"1" fargOCA.DiskPhysic
fargOCA.PolarGrid o-->"1" fargOCA.DiskGrid
fargOCA.GasDisk o-->"1" fargOCA.DiskDesc
fargOCA.GasDisk o-->"1" fargOCA.PlanetarySystem
fargOCA.GasDisk *--> fargOCA.PolarGrid: pressure\n soundSpeed\n density\n viscosity
fargOCA.GasDisk "1"*-->"1" fargOCA.GasDisk::Velocity
fargOCA.GasDisk::Velocity *--> fargOCA.PolarGrid: radial\n phi\n theta
```
## The polar grid object.
The most part of the program is spent manipulating **PolarGrid**[^2] instances. A polar grid is basically a 3D field of continuous floating point data organized on a grid with as `[nr radial][ni layer][ns sector]` if we use $`nr*ni*ns`$ grids.
This object only store the data as a [std::valarray<double>](http://www.cplusplus.com/reference/valarray/)[^4] object field, but also export it as an old fashioned C pointer[^3].
## The disk description
The disk geometry and physic configuration are described through a set of classes that are almost (almost) a [Singleton](https://en.wikipedia.org/wiki/Singleton_pattern) (because we do not need many of them). All object that need to have access to those information do so by referencing the appropriate instances.
The "almost" is important, as in the short term, it will allow close to trivial implementation of multi-grid decomposition by providing one instance by sub-domain.
* **DiskPhysic** provide the physical parameter of the disk. It is close to a direct mapping of the user provided property tree.
* **SystemPhysic** paly a similar role for the planetary system.
* **DiskGrid** is . It describe discretization of the (possibly flat) cylinder containing the gas. That include the grid points, aperture, etc.. and some usefull pre computed values. More than one **DiskGrid** object exist when the grid resolution is modified and a polar grid need to be re-mapped.
## Boundaries Conditions
Boundaries condition are implemented through **BoundariesHandler** [function objects](https://en.wikipedia.org/wiki/Command_pattern)[^5].
* All available handlers are registered by name in the application (user can add their own).
* In the configuration file, the user indicate the names of the requested handler.
* The application then bind those handler to the **GasDisk** object.
* The **SimulationDriver** object will then trigger them when required.
-------
[^1]: In particular, the diagram does not detail the configuration aspects in details.
[^2]: Not a very smart name, but **Field** was already used at the time. It might change in the future.
[^3]: Mostly for backward compatibility/laziness/lack of time.
[^4]: Intel has [special optimizations](https://software.intel.com/en-us/articles/using-improved-stdvalarray-with-intelr-c-compiler) for `std::valarray`, has not been tested yet.
[^5] Also called "callback".
\ No newline at end of file