The Structure
Below you can see the structure of an initialization file. The program loads the fosite module, declares some parameters and starts fosite. In order to do the latter the configuration needs to be build and the initial data needs to be set. This generally happens in the subroutines MakeConfig and InitData.
In order to get in touch with Fosite we use the Rayleigh-Taylor-instabilities in the following as an easy example case.
A Detailed Example
The Header
- In the very beginning all necessary modules need to be loaded. The module fosite_mod from fosite.f03 includes the subroutines to start fosite. It also includes common_dict, which provides a dictionary structure for generic data types.
- The second part of the header is the typical declaration section. Here the parameters for the setup can be declared, which are needed below in the configuration or initial data field. Some typical things that are always necessary are, e.g., the resolution and the field size or the output setup. This part can strongly vary according to your needs. Additionally a fosite object needs to be declared as allocatable. This is mandatory, since it is the main class which hosts all other classes, like sources, timedisc, ... . The whole configuration is also saved here.
- To finally run Fosite there is a fixed order of subroutines, which need to be called. They are mainly part of the fosite module. However, two very important subroutines need to be written on your own
- The MakeConfig: This is a dictionary which saves all the settings in one directory like the geometry and the resolution, the output and of course the source modules that are needed.
- The InitData: Here the initial data will be declared, which can be something very easy like a constant background density and velocity field or very complicated things, which might bring you in need to add additional routines in order to set up the initial data. In the next two parts we will discuss these two subroutines in detail.
Configuration Dictionary
At the end of the section you can see the whole MakeConfig subroutine. It gives back a dictionary, which is called config (see common_dict for details). There, all important settings for the simulation are stored and they are also written out to the data (depending on your output format). config itself is just a collection of dictionaries, where each ones handles a different field of numerics or physics. The syntax is mostly self-explaining. The dictionaries are of the form
You can store anything you want in the dictionaries. However, the keys that make sense are different for every module you might use.
As an example we take the first created dictionary mesh:
The class mesh says to approximate the flux integrals with the midpoint rule. For the key geometry you can chose between a wide variety of models, but here we use the easiest case of an cartesian geometry. Thus the geometry class is included in the mesh class.
Additionally you need to add some optional or necessary parameters, like in this case the resolution and the fieldsize. The available keys can be looked up at the module overview in the html pages. Alternatively you need to look into the code of the derived type directly and search for the GetAttr() calls. At these positions the dictionaries are read out, which is always done in the initialization routines of every class or subclass.
The order of the dictionaries is not always arbitrary. For example, in order to define the sources dictionary, you need first to define dictionaries for the specific sources. In our case below, we have a constant acceleration and a viscosity. These have its own parameters. Eventually, these dictionaries are included in the overall sources dictionary. If you want to try out a test simulation without a certain source, you can just comment out the part, like shown for the viscosity source term in our case. Finally, all dictionaries are collected and stored in config. This dictionary is passed through the routines in order to have the full configuration at hand.
The output is also controlled by a dictionary. In fileformat you can chose the way the output should look like. The recommanded output is XDMF or VTK*. These are readable by common viewers like Paraview or VisIt. An alternative dictionary compared to the one below could look like
Additonal parameters can be written out by setting the keys in the relating dictionaries. These are normally of the form "output/variable" with value 1 (yes) or 0 (no). For example the key/value pair *"output/volume" / 1* could be written in the mesh-dictionary in order to write out the volume of the cells.
Finally, the whole configuration subroutine could look like this:
Set Initial Data
The last thing to do is to set up the initial data. The easiest way is to define the known primitive variables pvar on the whole domain. At the end of the initialization you can observe these two routines:
The first line is converting the primitive variable to conservative ones in order to store a full set of parameters in the beginning. This call is necessary. The second is an info-call for your later logfiles. Here you can write down a reasonable description for your initial conditions.
Additional Resources
There are lots of other examples, where you can find inspiration for different initializations. Especially, if you want to know how to include gravitational source terms have a look at a self-graviting disk.