Peano
Loading...
Searching...
No Matches
acoustic.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
3import sympy
4
5"""
6We import the required modules for this project.
7We always need the 'peano4' module as this is our core project.
8Since we are creating a SymHyPE/ExaHyPE 2 application, we additionally
9need to import the 'exahype2' and 'symhype' modules.
10"""
11import peano4
12import exahype2
13import symhype
14
15"""
16We specify the space dimensions here.
17We support either 2- or 3-dimensional problems.
18"""
19dimensions = 2
20
21"""
22The number of finite volumes per axis in one patch.
23"""
24patch_size = 16
25
26"""
27The number of levels the mesh is refined.
28"""
29depth = 5
30
31"""
32The simulation end time.
33"""
34end_time = 1.0
35
36"""
37Choose domain size and offset.
38"""
39size = [10.0, 10.0, 10.0]
40offset = [0.0, 0.0, 0.0]
41
42"""
43Choose how often a snapshot is written.
44"""
45time_in_between_two_snapshots = end_time / 10
46# time_in_between_two_snapshots = 0 # Set to 0 to disable I/O
47
48"""
49Switch between 'Release', 'Debug', 'Asserts', 'Trace', 'Stats'.
50"""
51compile_mode = "Release"
52
53"""
54We first create a new ExaHyPE 2 project.
55For this, we specify the (nested) namespaces, the name of our main file and our executable name.
56"""
57my_project = exahype2.Project(
58 namespace=["tutorials", "symhype", "acoustic"],
59 project_name="Acoustic",
60 directory=".",
61 executable="Acoustic",
62)
63
64"""
65Add the Finite Volumes solver using named arguments.
66This is the way you can add further PDE terms.
67This requires the 'BlockStructured' toolbox and 'ExaHyPE' to be built.
68"""
69my_solver = exahype2.solvers.fv.godunov.GlobalAdaptiveTimeStep(
70 name="FVSolver",
71 patch_size=patch_size,
72 unknowns=dimensions + 1, # [p, u, v, (w)]
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"""
80We want to define our PDE symbolically.
81"""
82my_pde = symhype.FirstOrderConservativePDEFormulation(
83 unknowns=dimensions + 1, auxiliary_variables=0, dimensions=dimensions
84)
85p = my_pde.name_Q_entry(0, "p")
86v = my_pde.name_Q_entries(1, dimensions, "v")
87
88rho = sympy.symbols("rho")
89c = sympy.symbols("c")
90K0 = rho * c * c
91
92"""
93Define the equation system
94"""
95# Flux [unknowns, dimensions]
96if dimensions == 2:
97 my_pde.F[0, 0] = K0 * v[0]
98 my_pde.F[1, 0] = 1.0 / rho * p
99 my_pde.F[2, 0] = 0
100
101 my_pde.F[0, 1] = K0 * v[1]
102 my_pde.F[1, 1] = 0
103 my_pde.F[2, 1] = 1.0 / rho * p
104else:
105 my_pde.F[0, 0] = K0 * v[0]
106 my_pde.F[1, 0] = 1.0 / rho * p
107 my_pde.F[2, 0] = 0
108 my_pde.F[3, 0] = 0
109
110 my_pde.F[0, 1] = K0 * v[1]
111 my_pde.F[1, 1] = 0
112 my_pde.F[2, 1] = 1.0 / rho * p
113 my_pde.F[3, 1] = 0
114
115 my_pde.F[0, 2] = K0 * v[2]
116 my_pde.F[1, 2] = 0
117 my_pde.F[2, 2] = 0
118 my_pde.F[3, 2] = 1.0 / rho * p
119
120# Eigenvalues [unknowns, dimensions]
121if dimensions == 2:
122 my_pde.eigenvalues[0] = -c
123 my_pde.eigenvalues[1] = 0
124 my_pde.eigenvalues[2] = c
125else:
126 my_pde.eigenvalues[0] = -c
127 my_pde.eigenvalues[1] = 0
128 my_pde.eigenvalues[2] = 0
129 my_pde.eigenvalues[3] = c
130
131"""
132Since 'my_pde' only holds the PDE without initial- or boundary conditions,
133we still need to properly define initial- and boundary conditions.
134This gives us then a complete description of a 'scenario'.
135"""
136
137# Initial conditions
138my_pde.initial_values[0] = 0
139my_pde.initial_values[1] = 0
140my_pde.initial_values[2] = 0
141if dimensions == 3:
142 my_pde.initial_values[3] = 0
143
144# Boundary conditions
145my_pde.boundary_values[0] = 0
146my_pde.boundary_values[1] = 0
147my_pde.boundary_values[2] = 0
148if dimensions == 3:
149 my_pde.boundary_values[3] = 0
150
151# Source term
152sigma = sympy.symbols("sigma")
153t0 = sympy.symbols("t0")
154M0 = sympy.symbols("M0")
155t = sympy.symbols("t")
156
157max_h = sympy.symbols("MaxAdmissibleVolumeH")
158force = M0 * sympy.exp(-((t - t0) * (t - t0)) / (2.0 * sigma * sigma))
159
160if dimensions == 2:
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)) # p
163else:
164 point_source = sympy.sqrt(
165 (5 - my_pde.x[0]) ** 2 + (5 - my_pde.x[1]) ** 2 + (5 - my_pde.x[2]) ** 2
166 )
167 my_pde.sources[0] = sympy.Piecewise((force, point_source <= max_h), (0, True)) # p
168
169my_pde.sources[1] = 0
170my_pde.sources[2] = 0
171if dimensions == 3:
172 my_pde.sources[3] = 0
173
174my_pde.substitute_expression(rho, 2.7)
175my_pde.substitute_expression(c, 6.0)
176my_pde.substitute_expression(sigma, 0.1149)
177my_pde.substitute_expression(t0, 0.7)
178my_pde.substitute_expression(M0, 1000.0)
179
180"""
181Specify which implementation our solvers uses.
182Here we want to set the implementation we get from our symbolically defined PDE,
183i.e., we get the C++ implementation which is generated by SymHyPE.
184"""
185my_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(),
191)
192
193"""
194To see which variables (unknowns + auxiliary variables) we can visualise,
195let's add a plot description for the variables to our solver.
196"""
197my_solver.plot_description = my_pde.unknown_identifier_for_plotter()
198
199"""
200Add the solver to our project
201"""
202my_project.add_solver(my_solver)
203
204"""
205Configure some global parameters
206"""
207my_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],
216)
217
218"""
219This defines where the output files should go.
220If you omit this, output files are automatically put into the application's folder.
221"""
222my_project.set_output_path("solutions")
223
224"""
225Configure load balancer for parallel execution.
226"""
227my_project.set_load_balancer("new ::exahype2::LoadBalancingConfiguration")
228
229"""
230We need to set the location of our core libraries ('Peano4').
231This helps us to resolve any dependencies.
232Additionally, we specify the build mode which you can also change to a different mode.
233"""
234my_project.set_Peano4_installation(
235 "../../../", mode=peano4.output.string_to_mode(compile_mode)
236)
237
238"""
239We generate and grab the underlying core project of 'Peano4'.
240This gives us access to some functions we want to use to finalise and build this project.
241"""
242my_project = my_project.generate_Peano4_project(verbose=False)
243
244"""
245Finally, we want to build our project.
246First, all of the necessary glue code is generated in the application folder,
247then 'make' is invoked automatically which compiles the generated code and links against our core libraries
248and toolboxes which have been built before.
249You can also always invoke 'make' yourself to compile, or cleanup with 'make clean'.
250"""
251my_project.build(make=True, make_clean_first=True, throw_away_data_after_build=True)
252
253print("\nPDE is: ")
254print(my_pde.__str__())
255print(my_solver)
256print(my_project)