9We import the required modules for this project.
10We always need the 'peano4' module as this is our core project.
11Since we are creating an ExaHyPE 2 application, we additionally
12need to import the 'exahype2' module.
18We specify the space dimensions here.
19We support either 2- or 3-dimensional problems.
24The number of finite volumes per axis in one patch.
29The size of a finite volume/cell per axis.
34The simulation end time.
39Choose domain size and offset.
41size = [10.0, 10.0, 10.0]
42offset = [0.0, 0.0, 0.0]
45Choose how often a snapshot is written.
47time_in_between_two_snapshots = end_time / 100
51Switch between 'Release', 'Debug', 'Asserts', 'Trace', 'Stats'.
53compile_mode = peano4.output.CompileMode.Release
56We first create a new ExaHyPE 2 project.
57For this, we specify the (nested) namespaces, the name of our main file and our executable name.
60 namespace=[
"tutorials",
"exahype2",
"acoustic"],
61 project_name=
"Acoustic",
67Add the Finite Volumes solver using named arguments.
68This is the way you can add further PDE terms.
69This requires the 'BlockStructured' toolbox and 'ExaHyPE' to be built.
70Rusanov is the type of flux that is used to solve the Riemann problem at boundaries between cells.
74 patch_size=patch_size,
75 unknowns=dimensions + 1,
76 auxiliary_variables=0,
77 min_volume_h=volume_size,
78 max_volume_h=volume_size,
79 time_step_relaxation=0.5,
83We want to define our PDE symbolically.
84For this we use the 'symhype' package (not to be confused with 'sympy') from 'ExaHyPE'.
87 unknowns=dimensions + 1, auxiliary_variables=0, dimensions=dimensions
89p = my_pde.name_Q_entry(0,
"p")
90v = my_pde.name_Q_entries(1, dimensions,
"v")
92rho = sympy.symbols(
"rho")
97Define the equation system
101 my_pde.F[0, 0] = K0 * v[0]
102 my_pde.F[1, 0] = 1.0 / rho * p
105 my_pde.F[0, 1] = K0 * v[1]
107 my_pde.F[2, 1] = 1.0 / rho * p
109 my_pde.F[0, 0] = K0 * v[0]
110 my_pde.F[1, 0] = 1.0 / rho * p
114 my_pde.F[0, 1] = K0 * v[1]
116 my_pde.F[2, 1] = 1.0 / rho * p
119 my_pde.F[0, 2] = K0 * v[2]
122 my_pde.F[3, 2] = 1.0 / rho * p
126 my_pde.eigenvalues[0] = -c
127 my_pde.eigenvalues[1] = 0
128 my_pde.eigenvalues[2] = c
130 my_pde.eigenvalues[0] = -c
131 my_pde.eigenvalues[1] = 0
132 my_pde.eigenvalues[2] = 0
133 my_pde.eigenvalues[3] = c
136Since 'my_pde' only holds the PDE without initial- or boundary conditions,
137we still need to properly define initial- and boundary conditions.
138This gives us then a complete description of a 'scenario'.
142my_pde.initial_values[0] = 0
143my_pde.initial_values[1] = 0
144my_pde.initial_values[2] = 0
146 my_pde.initial_values[3] = 0
149my_pde.boundary_values[0] = 0
150my_pde.boundary_values[1] = 0
151my_pde.boundary_values[2] = 0
153 my_pde.boundary_values[3] = 0
156sigma = sympy.symbols(
"sigma")
157t0 = sympy.symbols(
"t0")
158M0 = sympy.symbols(
"M0")
159t = sympy.symbols(
"t")
161max_h = sympy.symbols(
"MaxAdmissibleVolumeH")
162force = M0 * sympy.exp(-((t - t0) * (t - t0)) / (2.0 * sigma * sigma))
165 point_source = sympy.sqrt((5 - my_pde.x[0]) ** 2 + (5 - my_pde.x[1]) ** 2)
166 my_pde.sources[0] = sympy.Piecewise((force, point_source <= max_h), (0,
True))
168 point_source = sympy.sqrt(
169 (5 - my_pde.x[0]) ** 2 + (5 - my_pde.x[1]) ** 2 + (5 - my_pde.x[2]) ** 2
171 my_pde.sources[0] = sympy.Piecewise((force, point_source <= max_h), (0,
True))
176 my_pde.sources[3] = 0
178my_pde.substitute_expression(rho, 2.7)
179my_pde.substitute_expression(c, 6.0)
180my_pde.substitute_expression(sigma, 0.1149)
181my_pde.substitute_expression(t0, 0.7)
182my_pde.substitute_expression(M0, 1000.0)
185Specify which implementation our solvers uses.
186Here we want to set the implementation we get from our symbolically defined PDE,
187i.e., we get the C++ implementation which is generated by ExaHyPE's 'symhype' package.
189my_solver.set_implementation(
190 initial_conditions=my_pde.implementation_of_initial_conditions(),
191 boundary_conditions=my_pde.implementation_of_boundary_conditions(),
192 flux=my_pde.implementation_of_flux(),
193 eigenvalues=my_pde.implementation_of_max_eigenvalue(),
194 source_term=my_pde.implementation_of_sources(),
198To see which variables (unknowns + auxiliary variables) we can visualise,
199let's add a plot description for the variables to our solver.
201my_solver.plot_description = my_pde.unknown_identifier_for_plotter()
204Add the solver to our project
206my_project.add_solver(my_solver)
209Configure some global parameters
211my_project.set_global_simulation_parameters(
212 dimensions=dimensions,
213 size=size[0:dimensions],
214 offset=offset[0:dimensions],
215 min_end_time=end_time,
216 max_end_time=end_time,
217 first_plot_time_stamp=0.0,
218 time_in_between_plots=time_in_between_two_snapshots,
219 periodic_BC=[
False,
False,
False],
223This defines where the output files should go.
224If you omit this, output files are automatically put into the application's folder.
226my_project.set_output_path(
"solution")
229If you only target a sequential execution, you can omit the load balancing.
230However, for a parallel build and execution you need to set load balancing.
231This requires the 'LoadBalancing' toolbox to be built.
232The type of load balancer can greatly impact the speedup and overall performance.
233For an overview of available load balancer refer to the documentation.
235my_project.set_load_balancing(
236 "toolbox::loadbalancing::strategies::SpreadOutOnceGridStagnates",
237 "new ::exahype2::LoadBalancingConfiguration()",
241We need to set the location of our core libraries ('Peano4').
242This helps us to resolve any dependencies.
243Additionally, we specify the build mode which you can also change to a different mode.
245my_project.set_Peano4_installation(
"../../../../", mode=compile_mode)
248We generate and grab the underlying core project of 'Peano4'.
249This gives us access to some functions we want to use to finalise and build this project.
251my_project = my_project.generate_Peano4_project(verbose=
True)
254Finally, we want to build our project.
255First, all of the necessary glue code is generated in the application folder,
256then 'make' is invoked automatically which compiles the generated code and links against our core libraries
257and toolboxes which have been built before.
258You can also always invoke 'make' yourself to compile, or cleanup with 'make clean'.
260my_project.build(make=
True, make_clean_first=
True, throw_away_data_after_build=
True)
263print(my_pde.__str__())