|
1 | | -# Custom problem generators |
| 1 | +# Standard problem generators |
2 | 2 |
|
3 | | -Different simulation setups in AthenaPK are controlled via the so-called problem generators. |
4 | | -New problem generators can easily be added and we are happy to accept and merge contibuted problem |
5 | | -generators by any user via pull requests. |
| 3 | +## Multi cloud shattering (`job/problem_id=shattering`) |
6 | 4 |
|
7 | | -## Addding a new problem generator |
| 5 | +This problem generator implements the basic multi cloud shattering setup |
| 6 | +following [Gronke & Oh 2020](https://doi.org/10.1093/mnrasl/slaa033G). |
8 | 7 |
|
9 | | -In general, four small steps are required: |
| 8 | +The initial conditions are currently hardcoded to a unit cube (though |
| 9 | +physical dimensions have to be assigned via units) with initially |
| 10 | +unit density (in code units) for the hot phase. |
10 | 11 |
|
11 | | -### 1. Add a new source file to the `src/pgen` folder |
| 12 | +In addition to specifying units, the problem generator can be configured via |
12 | 13 |
|
13 | | -The file shoud includes at least the `void ProblemGenerator(Mesh *pmesh, ParameterInput *pin, MeshData<Real> *md)` |
14 | | -function, which is used to initialize the data at the beginning of the simulation. |
15 | | -Alternatively, the `MeshBlock` version (`void ProblemGenerator(MeshBlock *pmb, ParameterInput *pin)`) can be used that |
16 | | -operates on a single block at a time rather than on a collection of blocks -- though this is not recommended from a performance point of view. |
17 | | - |
18 | | -The function (and all other functions in that file) should be encapsulated in their own namespace (that, ideally, is named |
19 | | -identical to the file itself) so that the functions name are unique across different problem generators. |
20 | | - |
21 | | -Tip: Do not write the problem generator file from scratch but mix and match from existing ones, |
22 | | -e.g., start with a simple one like [orszag_tang.cpp](../src/pgen/orszag_tang.cpp). |
23 | | - |
24 | | -### 2. Add new function(s) to `pgen.hpp` |
25 | | - |
26 | | -All callback functions, i.e., at least the `ProblemGenerator` plus additional optional ones (see step 5 below), |
27 | | -need to be added to [pgen.hpp](../src/pgen/pgen.hpp). |
28 | | -Again, just follow the existing pattern in the file and add the new function declarations with the appropriate namespace. |
29 | | - |
30 | | -### 3. Add callbacks to `main.cpp` |
31 | | - |
32 | | -All problem specific callback functions need to be enrolled in the [`main.cpp`](../src/main.cpp) file. |
33 | | -The selection (via the input file) is controlled by the `problem_id` string in the `<job>` block. |
34 | | -Again, for consistency it is recommended to pick a string that matches the namespace and problem generator file. |
35 | | - |
36 | | -### 4. Ensure new problem generator is compiled |
37 | | - |
38 | | -Add the new source file to [src/pgen/CMakeLists.txt](../src/pgen/CMakeLists.txt) so that it will be compiled |
39 | | -along all other problem generators. |
40 | | - |
41 | | -### 5. (Optional) Add more additional callback |
42 | | - |
43 | | -In addition to the `ProblemGenerator` that initializes the data, other callback functions exists |
44 | | -that allow to modify the behavior of AthenaPK on a problem specific basis. |
45 | | -See [Callback functions](#Callback-functions)] below for available options. |
46 | | - |
47 | | -### 6. (Optional but most likely required) Write an input file |
48 | | - |
49 | | -In theory, one can hardcode all paramters in the source file (like in the |
50 | | -[orszag_tang.cpp](../src/pgen/orszag_tang.cpp) problem generator) but it |
51 | | -prevents modification of the problem setup once the binary is compiled. |
52 | | - |
53 | | -The more common usecase is to create an input file that contains a problem specific |
54 | | -input block. |
55 | | -The convention here is to have a block named `<problem/NAME>` where `NAME` is the name |
56 | | -of the problem generator (or namespace used). |
57 | | -For example, the Sod shock tube problem generator processes the input file with lines like |
58 | | -``` |
59 | | - Real rho_l = pin->GetOrAddReal("problem/sod", "rho_l", 1.0); |
60 | | -``` |
61 | | -to set the density on the left hand side of the domain. |
62 | | - |
63 | | -## Callback functions |
64 | | - |
65 | | -### Source functions |
66 | | - |
67 | | -Additional (physical) source terms (e.g., the ones typically on the right hand side of |
68 | | -system of equations) can be added in various ways from an algorithmic point of view. |
69 | | - |
70 | | -#### Unsplit |
71 | | - |
72 | | -Unsplit sources are added at each stage of the (multi-stage) integration after the |
73 | | -(conserved) fluxes are calculated. |
74 | | -Therefore, the "conserved" variables should be updated using the "primitive" ones |
75 | | -and by taking into account the corresponding `dt` (more specifically the `beta*dt` |
76 | | -of the particular stage), see, for example, the `DednerSource` function in |
77 | | -[dedner_source.cpp](../src/hydro/glmmhd/dedner_source.cpp). |
78 | | - |
79 | | -Users can enroll a custom source function |
80 | | -```c++ |
81 | | -void MyUnsplitSource(MeshData<Real> *md, const Real beta_dt); |
82 | | -``` |
83 | | -by implementing a function with that signature and assigning it to the |
84 | | -`Hydro::ProblemSourceUnsplit` callback (currently in `main.cpp`). |
85 | | -
|
86 | | -Note, there is no requirement to call the function `MyUnsplitSource`. |
87 | | -
|
88 | | -#### Split first order (generally not recommended) |
89 | | -
|
90 | | -If for special circumstances sources need to be added in a fully operator split way, |
91 | | -i.e., the source function is only called *after* the full hydro (or MHD) integration, |
92 | | -a custom function |
93 | | -```c++ |
94 | | -void MyFirstOrderSource(MeshData<Real> *md, const parthenon::SimTime &tm); |
95 | | -``` |
96 | | -can be enrolled to the `Hydro::ProblemSourceFirstOrder` callback (currently in `main.cpp`). |
97 | | -The current `dt` can be accessed through `tm.dt`. |
98 | | - |
99 | | -Note, as the name suggests, this method is only first order accurate (while there |
100 | | -is no requirement to call the function `MyFirstOrderSource`). |
101 | | - |
102 | | - |
103 | | -#### Split second order (Strang splitting) |
104 | | - |
105 | | -Strang splitting achieves second order by interleaving the main hydro/MHD update |
106 | | -with a source update. |
107 | | -In practice, AthenaPK calls Strang split source with `0.5*dt` before the first stage of |
108 | | -each integrator and with `0.5*dt` after the last stage of the integrator. |
109 | | -Note that for consistency, a Strang split source terms should update both conserved |
110 | | -and primitive variables in all zones (i.e., also in the ghost zones as those |
111 | | -are currently not updated after calling a source function). |
112 | | - |
113 | | -Users can enroll a custom source function |
114 | | -```c++ |
115 | | -void MyStrangSplitSource(MeshData<Real> *md, const Real beta_dt); |
116 | | -``` |
117 | | -by implementing a function with that signature and assigning it to the |
118 | | -`Hydro::ProblemSourceStrangSplit` callback (currently in `main.cpp`). |
119 | | -
|
120 | | -Note, there is no requirement to call the function `MyStrangSplitSource`. |
121 | | -
|
122 | | -
|
123 | | -### Timestep restrictions |
124 | | -
|
125 | | -If additional problem specific physics are implemented (e.g., through the source |
126 | | -functions above) that require a custom timestep, it can be added via the |
127 | | -`ProblemEstimateTimestep` callback with the following signature |
128 | | -```c++ |
129 | | -Real ProblemEstimateTimestep(MeshData<Real> *md); |
130 | 14 | ``` |
131 | | - |
132 | | -The return value is expected to be the minimum value over all blocks in the |
133 | | -contained in the `MeshData` container, cf., the hydro/mhd `EstimateTimestep` function. |
134 | | -Note, that the hyperbolic CFL value is currently applied after the function call, i.e., |
135 | | -it is also applied to the problem specific function. |
136 | | - |
137 | | -### Additional initialization on startup (adding variables/fields, custom history output, ...) |
138 | | - |
139 | | -Sometimes a problem generator requires a more general processing of the input file |
140 | | -and/or needs to make certain global adjustments (e.g., adding a custom callback function |
141 | | -for the history output or adding a new field). |
142 | | -This can be achieved via modifying the AthenaPK "package" (currently called |
143 | | -`parthenon::StateDescriptor`) through the following function. |
144 | | -```c++ |
145 | | -void ProblemInitPackageData(ParameterInput *pin, parthenon::StateDescriptor *pkg) |
| 15 | +<problem/shattering> |
| 16 | +chi_i = 100 # initial overdensity |
| 17 | +T_cloud = 4e5 # initial temperature |
| 18 | +#reset_times = true # set by default |
146 | 19 | ``` |
147 | 20 |
|
148 | | -For example, the [src/pgen/turbulence.cpp](../[src/pgen/turbulence.cpp]) problem generator |
149 | | -add an additional field (here for an acceleration field) by calling |
150 | | -```c++ |
151 | | - Metadata m({Metadata::Cell, Metadata::Derived, Metadata::OneCopy}, |
152 | | - std::vector<int>({3})); |
153 | | - pkg->AddField("acc", m); |
154 | | -``` |
155 | | -in the `ProblemInitPackageData`. |
| 21 | +which sets initial overdensity and temperature of the clouds, which |
| 22 | +are initialized in pressure equilibrium with the hot phase. |
| 23 | +By default, following the paper the simulation times |
| 24 | +(i.e., `tlim` and the `dt` for outputs) are rescaled with respect to |
| 25 | +the relevant dynamical timescale (e.g., cooling timescales or sound crossing timescale), |
| 26 | +which is also reported on terminal upon simulation startup. |
156 | 27 |
|
157 | | -### Additional initialization on mesh creation/remeshing/load balancing |
| 28 | +Moreover, following details are currently hardcoded (following the choices in |
| 29 | +the paper), but can easily be modified in the code when needed: |
| 30 | +- the individual cloud radii are fixed to 0.125 (i.e., 1/8 of the box) |
| 31 | +- four clouds are seeded at positions `{0.5, 0.5, 0.5}, {0.45, 0.5, 0.55}, {0.5, 0.47, 0.42}, {0.53, 0.56, 0.5}` |
| 32 | +- initial perturpations are using a normal distribution with standard deviation of 0.01 |
158 | 33 |
|
159 | | -For some problem generators it is required to initialize data on "new" blocks. |
160 | | -These new blocks can, for example, be created during mesh refinement |
161 | | -(or derefinement) and this data is typically not active data (like |
162 | | -conserved or primitive variables as those are handled automatically) |
163 | | -but more general data. |
164 | | -Once example is the phase information in the turbulence driver that |
165 | | -does not vary over time but spatially (and therefore at a per block level). |
166 | 34 |
|
167 | | -The appropriate callback to enroll is |
168 | | -```c++ |
169 | | -void InitMeshBlockUserData(MeshBlock *pmb, ParameterInput *pin) |
170 | | -``` |
| 35 | +# More complex problem generators |
171 | 36 |
|
172 | | -### UserWorkAfterLoop |
173 | | -
|
174 | | -If additional work is required once the main loop finishes (i.e., once the |
175 | | -simulation reaches its final time) computations can be done inside the |
176 | | -```c++ |
177 | | -void UserWorkAfterLoop(Mesh *mesh, ParameterInput *pin, parthenon::SimTime &tm) |
178 | | -``` |
179 | | -callback function. |
180 | | -This is, for example, done in the linear wave problem generator to calculate the |
181 | | -error norms for convergence tests. |
182 | | - |
183 | | -### MeshBlockUserWorkBeforeOutput |
184 | | - |
185 | | -Sometimes it is desirable to further process data before an output file is written. |
186 | | -For this the |
187 | | -```c++ |
188 | | -void UserWorkBeforeOutput(MeshBlock *pmb, ParameterInput *pin) |
189 | | -``` |
190 | | -callback is available, that is called once every time right before a data output |
191 | | -(hdf5 or restart) is being written. |
192 | | -
|
193 | | -### Particles |
194 | | -
|
195 | | -#### Tracers |
196 | | -
|
197 | | -In order to allow custom seeding of tracer particles (per problem generator), the |
198 | | -`ProblemSeedInitialTracers` function can be defined. |
199 | | -```c++ |
200 | | -void ProblemSeedInitialTracers(Mesh *pmesh, ParameterInput *pin, parthenon::SimTime &tm); |
201 | | -``` |
202 | | -It is executed once when a simulation is started the very first time (i.e., it |
203 | | -is not called on subsequent restarts). |
204 | | -See the standard tracer seeding implementation[`SeedInitialTracers`](https://github.com/parthenon-hpc-lab/athenapk/blob/main/src/tracers/tracers.cpp) for reference on how to deposit particles. |
205 | | - |
206 | | - |
207 | | -To allow adding additional fields, the |
208 | | -```c++ |
209 | | -void ProblemInitTracerData(ParameterInput * pin, parthenon::StateDescriptor *tracer_pkg);``` |
210 | | -callback is available. |
211 | | -It is called at the end of the tracer package initialization and can be defined at the per-problem-generator level, see, e.g., the turbulence driver as an example. |
212 | | - |
213 | | -Similarly, a callback is available to fill those new fields (or more) via |
214 | | -```c++ |
215 | | -TaskStatus ProblemFillTracers(MeshData<Real> *md, parthenon::SimTime &tm, const Real dt); |
216 | | -``` |
217 | | -It is called right after the default `FillTracers` task in the driver. |
| 37 | +- [Galaxy Cluster and Cluster-like Problem Setup](cluster.md) |
| 38 | +- [Driven turbulence](turbulence.md) |
0 commit comments