Line data Source code
1 0 : \cond NEVER
2 : Distributed under the MIT License.
3 : See LICENSE.txt for details.
4 : \endcond
5 : # A Hitchhiker's Guide to Running SpECTRE {#beginners_guide}
6 :
7 : \tableofcontents
8 :
9 : SpECTRE can be a bit complicated to get started with, especially if you aren't
10 : familiar with our core concepts of task-based parallelism and Template
11 : Meta-Programming (TMP). However, <a
12 : href="https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Don't_Panic">
13 : Don't Panic</a>. This guide aims to get you introduced to running,
14 : visualizing, editing, and then rebuilding SpECTRE to give you a feel for what
15 : SpECTRE is all about, all on your own laptop! Hopefully by the end of this guide
16 : you'll feel comfortable enough to look at other executables and maybe even
17 : venture into the code itself!
18 :
19 : ## Prerequisites
20 :
21 : To start off, you'll need to obtain an environment to build and run SpECTRE in.
22 : You could try and install all the dependencies yourself, but that is very
23 : tedious and very error prone. Instead, we provide a
24 : [Docker](https://docs.docker.com/get-docker/) container with all the
25 : dependencies pre-installed for you to use. The container also has the SpECTRE
26 : repository cloned in it already so you don't have to worry about getting it
27 : yourself. To obtain the docker image, run
28 :
29 : ```
30 : docker pull sxscollaboration/spectre:demo
31 : ```
32 :
33 : Another program you will need for this tutorial is
34 : [Paraview](https://www.paraview.org/download/) for visualizing the output. You
35 : specifically will need version 5.10.1 for this tutorial.
36 :
37 : If you'd like to use VSCode, the tutorial also has instructions for how to start
38 : in VSCode as well.
39 :
40 : ## Into the Container
41 :
42 : For both a terminal and VSCode, create the container in a terminal and start it.
43 :
44 : ```
45 : docker create --rm --name spectre_demo -p 11111:11111 \
46 : -i -t sxscollaboration/spectre:demo /bin/bash
47 : ```
48 : ```
49 : docker start spectre_demo
50 : ```
51 :
52 : We connect port `11111` on your local machine to port `11111` of the container
53 : so we can use Paraview. The `--rm` will delete the container when you stop it.
54 : This won't put you into the container, only start it in the background.
55 :
56 : You can also run a [Jupyter](https://jupyter.org/index.html) server for
57 : accessing the Python bindings (see \ref spectre_using_python) or running Jupyter
58 : notebooks. To do so, append another `-p` option with your specified port, e.g.
59 : `-p 8000:8000`. You can chain as many `-p` options as you want to expose more
60 : ports.
61 :
62 : The SpECTRE repository is located at `/work/spectre` inside the container.
63 :
64 :
65 : ### With a Terminal {#with_terminal}
66 :
67 : To hop in the container from a terminal, simply type
68 :
69 : ```
70 : docker attach spectre_demo
71 : ```
72 :
73 : and now you're in the container!
74 :
75 : ### With VSCode
76 :
77 : If you're using VSCode, you'll need the `Remote-Containers` extension to be
78 : able to access the container. Once you have it, open the
79 : [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette)
80 : and run the following commands.
81 :
82 : 1. `Remote-Containers: Attach to Running Container` - you should see the
83 : container `spectre_demo` that's currently running. Select that.
84 : 2. `File: Open Folder` - select `/work/spectre` which is where the repo is.
85 :
86 : Now you're in the container within VSCode! The terminal in VSCode will look
87 : identical to the one if you hadn't used VSCode.
88 :
89 : \note Any changes you make inside `/work/spectre` will be lost once you stop the
90 : container. If you'd like your changes to persist, get rid of the `--rm` flag in
91 : the `docker create` command.
92 :
93 : ## Compiling the code
94 :
95 : \note From here on out, all paths are assumed to be inside the container unless
96 : specified otherwise.
97 :
98 : The container already has a SpECTRE build pre-configured. Go to the build
99 : directory and compile the executables that we will use in this tutorial:
100 :
101 : ```sh
102 : cd /work/spectre/build
103 : make -j2 ExportCoordinates3D EvolveScalarAdvection2D all-pybindings
104 : ```
105 :
106 : This will compile the code on two cores. If you'd like to use more cores, use
107 : the `-j N` option where `N` is the number of cores.
108 :
109 : Once the executables are compiled they will be available in the
110 : `/work/spectre/build/bin` directory. The container already has this directory
111 : added to the `PATH` environment variable, so you can run executables from the
112 : command line right away:
113 :
114 : ```sh
115 : spectre --help
116 : ```
117 :
118 : ## Running ExportCoordinates3D
119 :
120 : First we will run the `ExportCoordinates3D` executable to visualize
121 : the coordinates of a binary black hole domain.
122 : Make a directory where you will run everything:
123 :
124 : ```
125 : mkdir /work/runs
126 : cd /work/runs
127 : ```
128 :
129 : Copy over the input file
130 : `/work/spectre/tests/InputFiles/ExportCoordinates/InputTimeDependent3D.yaml`
131 : into your `/work/runs` directory. To run the executable, do
132 :
133 : ```
134 : spectre run InputTimeDependent3D.yaml
135 : ```
136 :
137 : This will run it on one core. If you'd like to use more cores, add the `-j N`
138 : option where `N` is the number of cores. After this finishes you should
139 : see two `H5` files in your run directory:
140 :
141 : 1. ExportCoordinates3DVolume0
142 : 2. ExportCoordinates3DReductions
143 :
144 : The `Volume` file is where we store data from every element in our domain, like
145 : the coordinates or the metric. The `Reductions` file is for more global
146 : quantities like the minimum grid spacing over all the elements in our domain.
147 :
148 : \note Next time you run the executable, you will have to either move or delete
149 : the existing `H5` files as SpECTRE will error if it detects that an output file
150 : already exists. This is to prevent you from accidentally overwriting data.
151 : You can also use the `--force / -f` and `--clean-output / -C` flags to have
152 : `spectre run` delete the existing files before running the executable.
153 :
154 : ## Visualizing our BBH Coordinates
155 :
156 : Now it's time to use Paraview to visualize the coordinates we use for our BBH
157 : evolutions! SpECTRE will actually export the physical frame coordinates for
158 : every executable we have because they are a really useful diagnostic to have. We
159 : are just using the ExportCoordinates executable here so that you don't have to
160 : run a BBH evolution on your laptop which probably wouldn't work because of
161 : memory requirements.
162 :
163 : Before we get to Paraview, we have to tell paraview how to actually use the
164 : coordinates in the `Volume` `H5` file. To do this we have a tool called
165 : `generate-xdmf` in our Python command-line interface. Inside the `runs`
166 : directory where you have the `H5` files, run
167 :
168 : ```
169 : spectre generate-xdmf \
170 : --subfile-name element_data --output BBH_Coords \
171 : ExportCoordinates3DVolume*h5
172 : ```
173 :
174 : We output volume data per node so we append the
175 : node number to each volume file we have. Since you're most likely running on a
176 : laptop, you'll only be running on one node so you should only get one output
177 : file for the volume. The `--subfile-name` argument is the group name inside the
178 : `H5` file where the data is stored (groups can be checked by
179 : `h5ls -r FILE_NAME`). `generate-xdmf` will generate a file called
180 : `BBH_Coords.xmf`. Make sure to keep this `.xmf` file next to the volume file it
181 : was generated from. It uses relative paths to find the volume file which means
182 : if you move it, you won't be able to visualize anything.
183 :
184 : ### Attaching Paraview
185 :
186 : This is where we actually need Paraview. We have a headless (no GUI) vesion of
187 : paraview inside the container which we will refer to as the "server". To start
188 : the Paraview server, run
189 :
190 : ```
191 : pvserver &
192 : ```
193 :
194 : The `&` is so that the server runs in the background. If you hit `Enter` a
195 : couple times you'll get back to being able to type commands. You should see some
196 : output similar to
197 :
198 : ```
199 : Waiting for client...
200 : Connection URL: cs://92bbb69f2af2:11111
201 : Accepting connection(s): 92bbb69f2af2:11111
202 : ```
203 :
204 : This means it's waiting for you to connect some external Paraview session (the
205 : "client") to the server. Now, ***outside*** the container, start a session of
206 : Paraview 5.10.1. (Again, you must use this version otherwise it won't work
207 : properly.) Go to `File > Connect`. Click `Add Server`. Name it whatever you
208 : want, but keep the Host as `localhost`, the Server Type as `Client/Server`, the
209 : Port as `11111` (remember the `-p 11111:11111` flag from the docker command?).
210 : Here's a snapshot of what it should look like before you configure.
211 :
212 : \image html paraview_server.png "Paraview server settings"
213 :
214 : Hit `Configure`, then hit `Save` (we don't care about the launch configuration).
215 : Now you should see a list of your configured servers. Select the one you just
216 : created and hit `Connect`. It may take a minute or two to connect to the server,
217 : but once you do on the left you'll see something like
218 :
219 : \image html paraview_connect.png "Successfully connected Paraview to a server"
220 :
221 : \note If you close your client, the server will stop and you won't be able to
222 : reconnect. You'll have to restart the server in the container.
223 :
224 : ### Open the XMF File in Paraview Client {#open_xmf}
225 :
226 : Now that you have Paraview connected to the container, open the `BBH_Coords.xmf`
227 : file you just generated inside Paraview (the paths you'll see are the ones in
228 : the container, not your filesystem). You may be prompted to choose which XDMF
229 : reader to use. Choose the `XDMF Reader` option. The `Xdmf3` options won't work.
230 : Once you choose a reader, on the left, you'll see
231 :
232 : \image html beginners_paraview_left.png "Paraview side-bar"
233 :
234 : You can uncheck all the boxes in the `Point Arrays` section as they aren't
235 : necessary for visualizing the coordinates. Then hit `Apply`. Now you should see
236 : a solid sphere. This isn't super helpful. In the top bar you should see a
237 : dropdown to change the style that the points are plotted in. Select `Surface
238 : With Edges` like so. (Note: Your top bar may look slightly different from this
239 : depending on what version of `Paraview` you have.)
240 :
241 : \image html beginners_paraview_top.png "Paraview top-bar"
242 :
243 : Now you'll have a solid sphere with highlighted lines. To view the interior of
244 : the domain, you'll need to add a filter. To access the filters, navigate to
245 : `Filters` on the top menu bar, hover over `Alphabetical`, and search for your
246 : filter of choice. Probably the two most helpful filters
247 : for viewing the domain are the `Slice` and `Clip` filters. (Note that you'll
248 : have to choose the `Surface With Edges` option for each filter separately.)
249 :
250 : `Slice` is fairly self explanatory in that it will show you a single plane
251 : through the domain. Experiment with different planes to see our whole domain
252 : structure!
253 :
254 : The `Clip` filter will remove all points "above" a certain plane, where "above"
255 : is in the direction of the normal of that plane. If you combine two orthogonal
256 : `Clip`s, you can actually view a 3D wedge of our domain. Try moving the centers
257 : of the planes to view the domain around our excision surfaces! They have a lot
258 : of cool structure.
259 :
260 : If you'd like to read more about our BBH domain, you can look at the
261 : documentation for `domain::creators::BinaryCompactObject`.
262 :
263 : ## Evolution of BBH Coordinates
264 :
265 : Now that you are able to export and visualize our BBH domain coordinates at a
266 : single time, let's make a small movie of the coordinates as they evolve! To do
267 : this, we'll need to edit the input file `InputTimeDependent3D.yaml`. If you
268 : aren't familiar with YAML, it's a file type that uses key-value pairs to create
269 : actual objects in our C++ code. Feel free to experiment with keys and values in
270 : our input files. If you're unsure about what a key or value should be, we offer
271 : an easy way to check the options in the input file without running a whole
272 : simulation. In your `/work/runs` directory, if you run
273 :
274 : ```
275 : spectre validate InputTimeDependent3D.yaml
276 : ```
277 :
278 : the executable will parse and check the input file. If you made a typo, or added
279 : an incorrect key/value, a list of the available keys and their associated values
280 : will be printed.
281 :
282 : To change the number of times we output the coordinates, we'll need to go to the
283 : `%EventsAndTriggers:` block of the input file. This block is mainly where we
284 : specify which quantities we want to observe in a simulation or where we
285 : "Trigger" a specific "Event" to happen. (For more info on `%EventsAndTriggers`,
286 : see the \ref tutorial_events_and_triggers tutorial.) Currently in this input
287 : file we only have one Trigger/Event pair. The %Trigger is `TimeCompares:` and
288 : the %Event is `Completion`. To have the simulation run longer, change the
289 : `Value:` under `TimeCompares:` to something larger. If you look at the
290 : `Evolution:` block above the `%EventsAndTriggers:` block, you'll see that the
291 : initial time step is `0.5`. The way this executable is set up, the coordinates
292 : will be exported every time step. So set the final time `Value:` under
293 : `TimeCompares:` to some larger multiple of `0.5` so that you'll have the
294 : coordinates at a bunch of different times (a final time of `20` is reasonable.
295 : Depending on how many cores you run on this should take a couple minutes).
296 :
297 : Then, run the executable just like you did above (remember to move or delete the
298 : existing `H5` files), run `generate-xdmf`, and open it in Paraview and apply
299 : some filters of your choice. We recommend using a `Slice` filter with the normal
300 : pointing in the `-z` direction. This is because our BBH domain rotates about the
301 : `z` axis. Now, in the top bar of Paraview, you should see a "Play" button that
302 : looks like a sideways triangle (see the second image in the \ref open_xmf
303 : section). If you click this, Paraview will step through all the timesteps in the
304 : output files and you'll be able to see the domain rotate a bit!
305 :
306 : Next, we encourage you to play with the other inputs that control how the domain
307 : evolves over time. These options are housed in the
308 :
309 : ```yaml
310 : DomainCreator:
311 : BinaryCompactObject:
312 : ...
313 : TimeDependentMaps:
314 : ExpansionMap:
315 : ...
316 : RotationMap:
317 : ...
318 : SizeMapA:
319 : ...
320 : SizeMapB:
321 : ...
322 : ```
323 :
324 : block of the input file. Since this tutorial is more about running the code, we
325 : won't go into too much detail about each option. However, in general:
326 :
327 : 1. `ExpansionMap` is a global map (all parts of the domain) that controls the
328 : separation between the excision surfaces
329 : 2. `RotationMap` is a global map that controls how the excision spheres rotate
330 : about each other
331 : 3. `SizeMap` is a local map only around the excision spheres (not in the wave
332 : zone) that control the compression of grid points.
333 :
334 : Play around with these values! You may get an error if you put something that's
335 : too unphysical, but this is a fairly consequence-free playground for you to
336 : explore so just try a different value.
337 :
338 : Now you have a movie of how BBH coordinates evolve in a SpECTRE simulation!
339 :
340 : ## Exploring DG+FD
341 :
342 : Now that you are able to run, and visualize SpECTRE, let's explore a feature
343 : that is fairly unique to SpECTRE and is really powerful for handling
344 : discontinuities and shocks in our simulations. We call this feature `DG+FD`
345 : (it's also sometimes referred to as just `subcell`).
346 :
347 : ### Description of DG+FD
348 :
349 : `FD` is the usual finite difference you are used to. All of the BSSN codes use
350 : finite difference for solving Einstein's equations. FD is very good at capturing
351 : shocks and discontinuities and is a very robust method, making it well suited
352 : for hydro problems and other systems that have shocks and discontinuities.
353 :
354 : `DG` stands for Discontinuous Galerkin. DG is a spectral method for representing
355 : a solution on a grid, meaning that instead of taking the difference between the
356 : function value at two points to get the derivative, it uses known basis
357 : functions to represent the solution. Then the derivative can be known
358 : analytically and you only need to supply the coefficients for the basis. DG
359 : works best for representing smooth solutions; ones with very few shocks and
360 : discontinuities (like GR in vacuum). This makes DG much faster than FD for
361 : smooth solutions.
362 :
363 : In SpECTRE, we combine these two different methods into one system to take
364 : advantage of the strengths of each. When we have a solution that is smooth in
365 : some parts of the domain, but has shocks in other parts, using only one of these
366 : methods has disadvantages. If we only used DG, we wouldn't be able to resolve
367 : the shocks very well driving the errors up a lot. If we only used FD, we'd be
368 : able to represent the solution well, but it would be computationally
369 : inefficient. So we combine DG+FD so that we only do DG in the parts of the
370 : domain where the solution is smooth, and switch to FD in parts where there may
371 : be a shock or discontinuity. The algorithm for switching between DG and FD is
372 : explained in this image.
373 :
374 : \image html dg_fd_schematic.png "Scheme for switching between DG and FD (credit: Nils Deppe)"
375 :
376 : If you'd like to learn more about how SpECTRE implements its DG+FD scheme, you
377 : can read [the paper](https://arxiv.org/abs/2109.11645) on the ArXiv.
378 :
379 : ### Running the Kuzmin Problem
380 :
381 : To demonstrate DG+FD, we will be evolving the \link
382 : ScalarAdvection::Solutions::Kuzmin Kuzmin \endlink problem using the
383 : `EvolveScalarAdvection2D` executable. This is a simple test problem that
384 : rotates a set of geometric shapes with uniform angular velocity, which can be
385 : used to evaluate how well a numerical code can handle discontinuities stably
386 : over time. Inside the container make a new directory `/work/runs2` where you
387 : will run it. Also copy the default input file in
388 : `/work/spectre/tests/InputFiles/ScalarAdvection/Kuzmin2D.yaml` to this new
389 : `/work/runs2` directory.
390 :
391 : ### Changing the Default Input File
392 :
393 : The default input file has very low resolution so we'll need to crank that up a
394 : bit. The way to do this is to change the initial refinement levels and initial
395 : number of grid points which are located in
396 :
397 : ```yaml
398 : DomainCreator:
399 : Rectangle:
400 : ...
401 : InitialRefinement: [x, y]
402 : InitialGridPoints: [x, y]
403 : ```
404 :
405 : `InitialRefinement:` represents how many times we split a `Block` in half in
406 : order to create `Element`s, which are the fundamental units of our domain. So an
407 : initial refinement of `[1, 1]` means we split a single Block into 4 elements
408 : (split in half once in each direction). For an initial refinement of `[2, 2]` we
409 : first do 1 refinement like before, and then split each of the resulting 4
410 : elements in half again in each direction, resulting in 16 total Elements. To
411 : determine the total number of Elements for a given refinement (same in all
412 : directions), just do $2^{\mathrm{Dim * Refinement}}$. If you're confused by
413 : the terminology we use to describe the domain, we have a \ref domain_concepts
414 : guide that explains all terms related to our domain.
415 :
416 : `InitialGridPoints` represents the number of grid points per dimension in each
417 : Element after the final refinement has been applied. So if we had an initial
418 : refinement of `[2, 2]` like above and then initial grid points `[3, 3]` in each
419 : Element, we'd have a total of 9x16=144 grid points.
420 :
421 : As for actual numbers to use, you can experiment to see what gives good,
422 : well-resolved results. You'll definitely need more refinement than the default
423 : input file, but since refinement scales exponentially, this can become very
424 : expensive very quickly. On a laptop, you probably shouldn't go higher than
425 : refinement `[6, 6]`. As for grid points, this will depend on how much refinement
426 : you have. If you have a ton of small elements, you won't need too many grid
427 : points to resolve the solution; something like `[4, 4]` would work. If you don't
428 : have a lot of refinement, you may want more grid points if you still want to
429 : resolve your solution. For a DG scheme, increasing the number of grid points (p
430 : refinement) reduces the numerical error exponentially where the solution is
431 : smooth, so computational resources are used more effectively. However, to
432 : resolve shocks and discontinuities we have to refine the domain into more and
433 : smaller elements instead (h refinement). Striking the most effective balance
434 : between h and p refinement in different parts of the domain is the job of an
435 : adaptive mesh refinement (AMR) algorithm.
436 :
437 : The default input file only runs for a few time steps so we'll want to make this
438 : run longer so we can actually see some evolution. From the documentation of the
439 : \link ScalarAdvection::Solutions::Kuzmin Kuzmin \endlink system, the solution
440 : will rotate with an angular velocity of `1.0` (in code units). Thus, to do a
441 : full orbit, it will take `6.28` code units of time. In the `%EventsAndTriggers:`
442 : block of the input file, we see that the `Completion` event is triggered by the
443 : `Slabs` trigger. We could, in theory, calculate out how many slabs `6.28` code
444 : units is using the time step, but that's super tedious. Instead let's trigger
445 : completion using the `TimeCompares` trigger instead. We used this before when
446 : exporting the BBH coordinates, so just copy over the yaml block and change the
447 : `Value:`.
448 :
449 : Your final `%EventsAndTriggers:` block should look something like this:
450 :
451 : ```yaml
452 : EventsAndTriggers:
453 : - Trigger:
454 : TimeCompares:
455 : Comparison: GreaterThanOrEqualTo
456 : Value: 6.28
457 : Events:
458 : - Completion
459 : ...
460 : ```
461 :
462 : Now you should be ready to run the executable and get some output. Here, you
463 : will almost definitely benefit by running this on many cores by adding the
464 : `-j N` flag to the command you use to run the executable. Since we use lots
465 : of smaller elements, we distribute these over the available resources via a
466 : \link domain::BlockZCurveProcDistribution space filling curve \endlink to speed
467 : things up.
468 :
469 : ```
470 : spectre run Kuzmin2D.yaml -j4
471 : ```
472 :
473 : ### Visualizing the Kuzmin Problem
474 :
475 : Once your run finishes, extract the volume data with `generate-xdmf` using
476 :
477 : ```
478 : spectre generate-xdmf \
479 : --file-prefix ScalarAdvectionKuzmin2DVolume \
480 : --subfile-name VolumeData --output kuzmin_problem
481 : ```
482 :
483 : (Note that the `subfile-name` is different than before because it was different
484 : in the input file) and load it into Paraview once again. We are only interested
485 : in the quantity `U` which is the scalar field we were evolving. You can uncheck
486 : any other boxes. So now, instead of coordinates on your screen, you should see a
487 : large square colored by the solution profile described in the \link
488 : ScalarAdvection::Solutions::Kuzmin Kuzmin \endlink system. You should also
489 : notice that there are smaller squares that don't touch each other in the middle
490 : of the domain and on the edges there are large sections that are continuous.
491 : These are the FD and DG grids, respectively. If you go to the top bar in
492 : Paraview and change how you view the grid to `Surface With Edges`, this will
493 : become even more apparent.
494 :
495 : You will notice that the FD grid is mostly around where the interesting features
496 : are in the solution profile; the cylinder with a wedge cut out, the cone, and
497 : the hump. And then the DG grid is mostly where the solution should be zero
498 : towards the boundary of the domain (i.e. the very smooth part). So right from
499 : the start, you can see that we are saving computational effort by only doing the
500 : expensive, yet robust, method (FD) where it is necessary and the efficient
501 : method (DG) everywhere else where the solution is smooth.
502 :
503 : Now hit the "Play" button in the top bar of Paraview and watch the solution
504 : evolve. You'll notice that the elements in the domain switch back and forth
505 : between FD and DG. They do so in such a way that the elements will switch to FD
506 : when an interesting feature enters the element and then switch back to DG once
507 : the feature leaves. In this way, we are able to actually track shocks and
508 : discontinuities in real time in our solution by where the code switches to using
509 : FD instead of DG. This is extremely useful for expensive GRMHD simulations where
510 : we only want to do FD at a shock boundary, yet that shock boundary is moving
511 : through the domain. We are able to dynamically track this shock and resolve it
512 : well with FD, then switch back to DG after the shock passes through and the
513 : solution has settled down again.
514 :
515 : A pretty cool filter you can add is `Warp By Scalar`. In the left panel, choose
516 : the solution variable `U` as the scalar to use and hit `Apply`. In the viewing
517 : panel there should be a `2D` or `3D` button that you can toggle to make the view
518 : 3D. Once you do that you should be able to see that the height of the feature is
519 : your solution `U`. If you change the grid to `Surface With Edges` you can see
520 : the FD or DG grids warp with the solution. And if you hit "Play" it'll rotate
521 : around and you'll see the features moving in 3D! (Don't worry if you can't find
522 : this filter. Not all versions of Paraview may have it.)
523 :
524 : We encourage you to play around with the refinement and grid points before the
525 : next section to get a feel for how each changes the runtime and accuracy of
526 : solution.
527 :
528 : ## Editing the Kuzmin System
529 :
530 : Hopefully now you feel comfortable enough running SpECTRE that you
531 : can get the default input file for the pre-built executables, edit it, and run
532 : it. Now we are going to try our hand at actually editing some code in SpECTRE
533 : and then building SpECTRE. We're going to stick with the \link
534 : ScalarAdvection::Solutions::Kuzmin Kuzmin \endlink system and add a new feature
535 : to the solution profile!
536 :
537 : You can find the files for the Kuzmin system at
538 : `/work/spectre/src/PointwiseFunctions/AnalyticSolutions/ScalarAdvection/
539 : Kuzmin.?pp`.
540 : In the `hpp` file, you'll see a lot of Doxygen documentation and then the actual
541 : Kuzmin class. The only function that you will need to care about is
542 :
543 : ```cpp
544 : template <typename DataType>
545 : tuples::TaggedTuple<ScalarAdvection::Tags::U> variables(
546 : const tnsr::I<DataType, 2>& x, double t,
547 : tmpl::list<ScalarAdvection::Tags::U> /*meta*/) const;
548 : ```
549 :
550 : All of our analytic solutions have a function similar to this that will set the
551 : value corresponding to the tag in the return type. If you're unfamiliar with
552 : tags in SpECTRE, you can look at these sections for an explanation, \ref
553 : databox_a_taggedtuple_databox and \ref databox_a_proper_databox. However, it's
554 : basically just a fancy way of doing a compile-time key/value pair. The tag is
555 : the key, and the value is whatever you want it to be. In our case, the value is
556 : a tensor, representing the solution.
557 :
558 : The definition of this function in the `cpp` file is where you will be editing
559 : the actual Kuzmin solution. Towards the bottom of this function, there is a
560 : `for` loop that sets the solution at every grid point. This is where you will
561 : add in a new feature to the solution.
562 :
563 : You can pick any feature you want to add, so long as it's inside the domain
564 : bounds of `[0,1]x[0,1]` and centered around `(0.75, 0.5)`. This is because of
565 : how the kuzmin solution is set up with existing features at `(0.25, 0.5); (0.5,
566 : 0.25); (0.5, 0.75)`. If you're having trouble thinking of a feature to add try
567 : one of the following features:
568 :
569 : - Square centered at `(0.75, 0.5)` with solution value `1.0`
570 : - Side length `0.1` (any larger and it might interfere with the other
571 : features)
572 : - Circle of radius `0.045` centered on the square with value `0.0`
573 : - Triangle centered at `(0.75, 0.5)` with one corner facing in the `+x`
574 : direction with solution value `1.0`
575 : - Square centered at `(0.75, 0.5)`
576 : - Side length `0.1` (any larger and it might interfere with the other
577 : features)
578 : - Left half of the square has value `1.0` and right half of the square has
579 : value `0.5`
580 :
581 : \note The more detailed you make your feature, the more resolution you will need
582 : to resolve it.
583 :
584 : ### Re-building SpECTRE
585 :
586 : Once you have your feature coded up, go ahead and save your changes. Now we will
587 : build SpECTRE! Go to the `/work/spectre/build` directory. This is where you have
588 : to be in order to build SpECTRE. We use [CMake](https://cmake.org/) to configure
589 : our build directory. However, since the executables are already pre-built, this
590 : means the build directory is already configured! So you don't have to worry
591 : about `CMake` for now. If you wanted to reconfigure, for example using a
592 : different compiler, then you'd have to run `CMake`. If you want to learn more
593 : about how we use `CMake`, take a look at the \ref common_cmake_flags developers
594 : guide.
595 :
596 : To build the Kuzmin executable, run
597 :
598 : ```
599 : make EvolveScalarAdvection2D
600 : ```
601 :
602 : This should be very fast because you only edited a `cpp` file. Congrats! You've
603 : just built SpECTRE!
604 :
605 : Now re-run the executable in your `/work/runs2` directory. Hopefully everything
606 : works and you get some output. When you plot it in Paraview, it should look
607 : almost the same as before except your feature will be there too rotating with
608 : the others! How cool! You can also see if your feature needs FD or DG more by
609 : how much it switches back and forth.
610 :
611 : Experiment some more with either different features or different resolution!
612 :
613 : ## Conclusions
614 :
615 : Congrats! You've made it through the tutorial! If you only want to run our
616 : pre-built executables, you have all the tools necessary to run, visualize, and
617 : re-build them. If you want a full list of our executables, do
618 : `make list` in the build directory. This will also include our `Test_`
619 : executables which you can just ignore.
620 :
621 : In an already configured build directory, all you have to do to build a new
622 : executable is
623 :
624 : ```
625 : make ExecutableName
626 : ```
627 :
628 : and then you can copy the default input file from
629 : `/work/spectre/tests/InputFiles` and run it. Running an executable with the
630 : `--help` flag will give a description of what system is being evolved and the
631 : input options necessary.
|