Peano
euler.py
Go to the documentation of this file.
1 # This file is part of the ExaHyPE2 project. For conditions of distribution and
2 # use, please see the copyright notice at www.peano-framework.org
3 import sympy
4 
5 """
6 We import the required modules for this project.
7 We always need the 'peano4' module as this is our core project.
8 Since we are creating a SymHyPE/ExaHyPE 2 application, we additionally
9 need to import the 'exahype2' and 'symhype' modules.
10 """
11 import peano4
12 import exahype2
13 import symhype
14 
15 """
16 We specify the space dimensions here.
17 We support either 2- or 3-dimensional problems.
18 """
19 dimensions = 2
20 
21 """
22 The number of finite volumes per axis in one patch.
23 """
24 patch_size = 16
25 
26 """
27 The number of levels the mesh is refined.
28 """
29 depth = 5
30 
31 """
32 The simulation end time.
33 """
34 end_time = 1.0
35 
36 """
37 Choose domain size and offset.
38 """
39 size = [1.0, 1.0, 1.0]
40 offset = [0.0, 0.0, 0.0]
41 
42 """
43 Choose how often a snapshot is written.
44 """
45 time_in_between_two_snapshots = end_time / 10
46 # time_in_between_two_snapshots = 0 # Set to 0 to disable I/O
47 
48 """
49 Switch between 'Release', 'Debug', 'Asserts', 'Trace', 'Stats'.
50 """
51 compile_mode = "Release"
52 
53 """
54 We first create a new ExaHyPE 2 project.
55 For this, we specify the (nested) namespaces, the name of our main file and our executable name.
56 """
57 my_project = exahype2.Project(
58  namespace=["tutorials", "symhype", "euler"],
59  project_name="Euler",
60  directory=".",
61  executable="Euler",
62 )
63 
64 """
65 Add the Finite Volumes solver using named arguments.
66 This is the way you can add further PDE terms.
67 This requires the 'BlockStructured' toolbox and 'ExaHyPE' to be built.
68 """
69 my_solver = exahype2.solvers.fv.godunov.GlobalAdaptiveTimeStep(
70  name="FVSolver",
71  patch_size=patch_size,
72  unknowns=dimensions + 2, # [rho, u, v, (w), e]
73  auxiliary_variables=0,
74  min_volume_h=(1.1 * min(size[0:dimensions]) / (3.0**depth)),
75  max_volume_h=(1.1 * min(size[0:dimensions]) / (3.0**depth)),
76  time_step_relaxation=0.5,
77 )
78 
79 """
80 We want to define our PDE symbolically.
81 """
82 my_pde = symhype.FirstOrderConservativePDEFormulation(
83  unknowns=dimensions + 2, auxiliary_variables=0, dimensions=dimensions
84 )
85 
86 """
87 Give entries in input vector symbolic names. We first declare the constant
88 gamma. Then we tell the solver how we would like to name the Q entries.
89 """
90 gamma = sympy.symbols("gamma")
91 # First scalar is density
92 rho = my_pde.name_Q_entry(0, "rho")
93 # Momentum: Entries 1-dimensions (C counting style) holds j vector
94 # (Note: To get the velocities we need to divide with the density)
95 j = my_pde.name_Q_entries(1, dimensions, "j")
96 # Energy
97 E = my_pde.name_Q_entry(dimensions + 1, "E")
98 # Pressure
99 p = (gamma - 1) * (E - 1 / 2 * symhype.dot(j, j) / rho)
100 
101 """
102 Define the equation system
103 """
104 # Flux [unknowns, dimensions]
105 my_pde.F[0, :] = j
106 my_pde.F[1 : dimensions + 1, :] = 1 / rho * symhype.outer(
107  j, j
108 ) + p * sympy.eye(dimensions)
109 my_pde.F[dimensions + 1, :] = 1 / rho * j * (E + p)
110 
111 # Eigenvalues [unknowns, dimensions]
112 c = sympy.sqrt(gamma * p / rho)
113 u = j / rho # Velocities
114 if dimensions == 3:
115  my_pde.eigenvalues[0] = [u[0] - c, u[1] - c, u[2] - c]
116  my_pde.eigenvalues[1] = [u[0], u[1], u[2]]
117  my_pde.eigenvalues[2] = [u[0], u[1], u[2]]
118  my_pde.eigenvalues[3] = [u[0], u[1], u[2]]
119  my_pde.eigenvalues[4] = [u[0] + c, u[1] + c, u[2] + c]
120 else:
121  my_pde.eigenvalues[0] = [u[0] - c, u[1] - c]
122  my_pde.eigenvalues[1] = [u[0], u[1]]
123  my_pde.eigenvalues[2] = [u[0], u[1]]
124  my_pde.eigenvalues[3] = [u[0] + c, u[1] + c]
125 
126 my_pde.substitute_expression(gamma, 1.4)
127 
128 """
129 Since 'my_pde' only holds the PDE without initial- or boundary conditions,
130 we still need to properly define initial- and boundary conditions.
131 This gives us then a complete description of a 'scenario'.
132 """
133 
134 # Initial conditions as specified in the documentation.
135 my_pde.initial_values[0] = 1.0 # rho
136 my_pde.initial_values[1] = 0 # u
137 my_pde.initial_values[2] = 0 # v
138 
139 if dimensions == 2:
140  volume_centre = sympy.sqrt((0.5 - my_pde.x[0]) ** 2 + (0.5 - my_pde.x[1]) ** 2)
141  my_pde.initial_values[3] = sympy.Piecewise(
142  (1.0, volume_centre < 0.2), (1.01, True)
143  ) # e
144 else:
145  volume_centre = sympy.sqrt(
146  (0.5 - my_pde.x[0]) ** 2 + (0.5 - my_pde.x[1]) ** 2 + (0.5 - my_pde.x[2]) ** 2
147  )
148  my_pde.initial_values[3] = 0 # w
149  my_pde.initial_values[4] = sympy.Piecewise(
150  (1.0, volume_centre < 0.2), (1.01, True)
151  ) # e
152 
153 """
154 Specify which implementation our solvers uses.
155 Here we want to set the implementation we get from our symbolically defined PDE,
156 i.e., we get the C++ implementation which is generated by SymHyPE.
157 """
158 my_solver.set_implementation(
159  initial_conditions=my_pde.implementation_of_initial_conditions(),
160  boundary_conditions=my_pde.implementation_of_homogeneous_Neumann_BC(),
161  flux=my_pde.implementation_of_flux(),
162  max_eigenvalue=my_pde.implementation_of_max_eigenvalue(),
163 )
164 
165 """
166 To see which variables (unknowns + auxiliary variables) we can visualise,
167 let's add a plot description for the variables to our solver.
168 """
169 my_solver.plot_description = my_pde.unknown_identifier_for_plotter()
170 
171 """
172 Add the solver to our project
173 """
174 my_project.add_solver(my_solver)
175 
176 """
177 Configure some global parameters
178 """
179 my_project.set_global_simulation_parameters(
180  dimensions=dimensions,
181  size=size[0:dimensions],
182  offset=offset[0:dimensions],
183  min_end_time=end_time,
184  max_end_time=end_time,
185  first_plot_time_stamp=0.0,
186  time_in_between_plots=time_in_between_two_snapshots,
187  periodic_BC=[False, False, False],
188 )
189 
190 """
191 This defines where the output files should go.
192 If you omit this, output files are automatically put into the application's folder.
193 """
194 my_project.set_output_path("solutions")
195 
196 """
197 Configure load balancer for parallel execution.
198 """
199 my_project.set_load_balancer("new ::exahype2::LoadBalancingConfiguration")
200 
201 """
202 We need to set the location of our core libraries ('Peano4').
203 This helps us to resolve any dependencies.
204 Additionally, we specify the build mode which you can also change to a different mode.
205 """
206 my_project.set_Peano4_installation(
207  "../../../", mode=peano4.output.string_to_mode(compile_mode)
208 )
209 
210 """
211 We generate and grab the underlying core project of 'Peano4'.
212 This gives us access to some functions we want to use to finalise and build this project.
213 """
214 my_project = my_project.generate_Peano4_project(verbose=False)
215 
216 """
217 Finally, we want to build our project.
218 First, all of the necessary glue code is generated in the application folder,
219 then 'make' is invoked automatically which compiles the generated code and links against our core libraries
220 and toolboxes which have been built before.
221 You can also always invoke 'make' yourself to compile, or cleanup with 'make clean'.
222 """
223 my_project.build(make=True, make_clean_first=True, throw_away_data_after_build=True)
224 
225 print("\nPDE is: ")
226 print(my_pde.__str__())
227 print(my_solver)
228 print(my_project)
static double min(double const x, double const y)