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.
16 We specify the space dimensions here.
17 We support either 2- or 3-dimensional problems.
22 The number of finite volumes per axis in one patch.
27 The number of levels the mesh is refined.
32 The simulation end time.
37 Choose domain size and offset.
39 size = [10.0, 10.0, 10.0]
40 offset = [0.0, 0.0, 0.0]
43 Choose how often a snapshot is written.
45 time_in_between_two_snapshots = end_time / 10
49 Switch between 'Release', 'Debug', 'Asserts', 'Trace', 'Stats'.
51 compile_mode =
"Release"
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.
57 my_project = exahype2.Project(
58 namespace=[
"tutorials",
"symhype",
"acoustic"],
59 project_name=
"Acoustic",
61 executable=
"Acoustic",
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.
69 my_solver = exahype2.solvers.fv.godunov.GlobalAdaptiveTimeStep(
71 patch_size=patch_size,
72 unknowns=dimensions + 1,
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,
80 We want to define our PDE symbolically.
82 my_pde = symhype.FirstOrderConservativePDEFormulation(
83 unknowns=dimensions + 1, auxiliary_variables=0, dimensions=dimensions
85 p = my_pde.name_Q_entry(0,
"p")
86 v = my_pde.name_Q_entries(1, dimensions,
"v")
88 rho = sympy.symbols(
"rho")
89 c = sympy.symbols(
"c")
93 Define the equation system
97 my_pde.F[0, 0] = K0 * v[0]
98 my_pde.F[1, 0] = 1.0 / rho * p
101 my_pde.F[0, 1] = K0 * v[1]
103 my_pde.F[2, 1] = 1.0 / rho * p
105 my_pde.F[0, 0] = K0 * v[0]
106 my_pde.F[1, 0] = 1.0 / rho * p
110 my_pde.F[0, 1] = K0 * v[1]
112 my_pde.F[2, 1] = 1.0 / rho * p
115 my_pde.F[0, 2] = K0 * v[2]
118 my_pde.F[3, 2] = 1.0 / rho * p
122 my_pde.eigenvalues[0] = -c
123 my_pde.eigenvalues[1] = 0
124 my_pde.eigenvalues[2] = c
126 my_pde.eigenvalues[0] = -c
127 my_pde.eigenvalues[1] = 0
128 my_pde.eigenvalues[2] = 0
129 my_pde.eigenvalues[3] = c
132 Since 'my_pde' only holds the PDE without initial- or boundary conditions,
133 we still need to properly define initial- and boundary conditions.
134 This gives us then a complete description of a 'scenario'.
138 my_pde.initial_values[0] = 0
139 my_pde.initial_values[1] = 0
140 my_pde.initial_values[2] = 0
142 my_pde.initial_values[3] = 0
145 my_pde.boundary_values[0] = 0
146 my_pde.boundary_values[1] = 0
147 my_pde.boundary_values[2] = 0
149 my_pde.boundary_values[3] = 0
152 sigma = sympy.symbols(
"sigma")
153 t0 = sympy.symbols(
"t0")
154 M0 = sympy.symbols(
"M0")
155 t = sympy.symbols(
"t")
157 max_h = sympy.symbols(
"MaxAdmissibleVolumeH")
158 force = M0 * sympy.exp(-((t - t0) * (t - t0)) / (2.0 * sigma * sigma))
161 point_source = sympy.sqrt((5 - my_pde.x[0]) ** 2 + (5 - my_pde.x[1]) ** 2)
162 my_pde.sources[0] = sympy.Piecewise((force, point_source <= max_h), (0,
True))
164 point_source = sympy.sqrt(
165 (5 - my_pde.x[0]) ** 2 + (5 - my_pde.x[1]) ** 2 + (5 - my_pde.x[2]) ** 2
167 my_pde.sources[0] = sympy.Piecewise((force, point_source <= max_h), (0,
True))
169 my_pde.sources[1] = 0
170 my_pde.sources[2] = 0
172 my_pde.sources[3] = 0
174 my_pde.substitute_expression(rho, 2.7)
175 my_pde.substitute_expression(c, 6.0)
176 my_pde.substitute_expression(sigma, 0.1149)
177 my_pde.substitute_expression(t0, 0.7)
178 my_pde.substitute_expression(M0, 1000.0)
181 Specify which implementation our solvers uses.
182 Here we want to set the implementation we get from our symbolically defined PDE,
183 i.e., we get the C++ implementation which is generated by SymHyPE.
185 my_solver.set_implementation(
186 initial_conditions=my_pde.implementation_of_initial_conditions(),
187 boundary_conditions=my_pde.implementation_of_boundary_conditions(),
188 flux=my_pde.implementation_of_flux(),
189 max_eigenvalue=my_pde.implementation_of_max_eigenvalue(),
190 source_term=my_pde.implementation_of_sources(),
194 To see which variables (unknowns + auxiliary variables) we can visualise,
195 let's add a plot description for the variables to our solver.
197 my_solver.plot_description = my_pde.unknown_identifier_for_plotter()
200 Add the solver to our project
202 my_project.add_solver(my_solver)
205 Configure some global parameters
207 my_project.set_global_simulation_parameters(
208 dimensions=dimensions,
209 size=size[0:dimensions],
210 offset=offset[0:dimensions],
211 min_end_time=end_time,
212 max_end_time=end_time,
213 first_plot_time_stamp=0.0,
214 time_in_between_plots=time_in_between_two_snapshots,
215 periodic_BC=[
False,
False,
False],
219 This defines where the output files should go.
220 If you omit this, output files are automatically put into the application's folder.
222 my_project.set_output_path(
"solutions")
225 Configure load balancer for parallel execution.
227 my_project.set_load_balancer(
"new ::exahype2::LoadBalancingConfiguration")
230 We need to set the location of our core libraries ('Peano4').
231 This helps us to resolve any dependencies.
232 Additionally, we specify the build mode which you can also change to a different mode.
234 my_project.set_Peano4_installation(
235 "../../../", mode=peano4.output.string_to_mode(compile_mode)
239 We generate and grab the underlying core project of 'Peano4'.
240 This gives us access to some functions we want to use to finalise and build this project.
242 my_project = my_project.generate_Peano4_project(verbose=
False)
245 Finally, we want to build our project.
246 First, all of the necessary glue code is generated in the application folder,
247 then 'make' is invoked automatically which compiles the generated code and links against our core libraries
248 and toolboxes which have been built before.
249 You can also always invoke 'make' yourself to compile, or cleanup with 'make clean'.
251 my_project.build(make=
True, make_clean_first=
True, throw_away_data_after_build=
True)
254 print(my_pde.__str__())
static double min(double const x, double const y)