Peano
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
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 = [10.0, 10.0, 10.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", "acoustic"],
59  project_name="Acoustic",
60  directory=".",
61  executable="Acoustic",
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 + 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 """
80 We want to define our PDE symbolically.
81 """
82 my_pde = symhype.FirstOrderConservativePDEFormulation(
83  unknowns=dimensions + 1, auxiliary_variables=0, dimensions=dimensions
84 )
85 p = my_pde.name_Q_entry(0, "p")
86 v = my_pde.name_Q_entries(1, dimensions, "v")
87 
88 rho = sympy.symbols("rho")
89 c = sympy.symbols("c")
90 K0 = rho * c * c
91 
92 """
93 Define the equation system
94 """
95 # Flux [unknowns, dimensions]
96 if 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
104 else:
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]
121 if dimensions == 2:
122  my_pde.eigenvalues[0] = -c
123  my_pde.eigenvalues[1] = 0
124  my_pde.eigenvalues[2] = c
125 else:
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 """
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'.
135 """
136 
137 # Initial conditions
138 my_pde.initial_values[0] = 0
139 my_pde.initial_values[1] = 0
140 my_pde.initial_values[2] = 0
141 if dimensions == 3:
142  my_pde.initial_values[3] = 0
143 
144 # Boundary conditions
145 my_pde.boundary_values[0] = 0
146 my_pde.boundary_values[1] = 0
147 my_pde.boundary_values[2] = 0
148 if dimensions == 3:
149  my_pde.boundary_values[3] = 0
150 
151 # Source term
152 sigma = sympy.symbols("sigma")
153 t0 = sympy.symbols("t0")
154 M0 = sympy.symbols("M0")
155 t = sympy.symbols("t")
156 
157 max_h = sympy.symbols("MaxAdmissibleVolumeH")
158 force = M0 * sympy.exp(-((t - t0) * (t - t0)) / (2.0 * sigma * sigma))
159 
160 if 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
163 else:
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 
169 my_pde.sources[1] = 0
170 my_pde.sources[2] = 0
171 if dimensions == 3:
172  my_pde.sources[3] = 0
173 
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)
179 
180 """
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.
184 """
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(),
191 )
192 
193 """
194 To see which variables (unknowns + auxiliary variables) we can visualise,
195 let's add a plot description for the variables to our solver.
196 """
197 my_solver.plot_description = my_pde.unknown_identifier_for_plotter()
198 
199 """
200 Add the solver to our project
201 """
202 my_project.add_solver(my_solver)
203 
204 """
205 Configure some global parameters
206 """
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],
216 )
217 
218 """
219 This defines where the output files should go.
220 If you omit this, output files are automatically put into the application's folder.
221 """
222 my_project.set_output_path("solutions")
223 
224 """
225 Configure load balancer for parallel execution.
226 """
227 my_project.set_load_balancer("new ::exahype2::LoadBalancingConfiguration")
228 
229 """
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.
233 """
234 my_project.set_Peano4_installation(
235  "../../../", mode=peano4.output.string_to_mode(compile_mode)
236 )
237 
238 """
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.
241 """
242 my_project = my_project.generate_Peano4_project(verbose=False)
243 
244 """
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'.
250 """
251 my_project.build(make=True, make_clean_first=True, throw_away_data_after_build=True)
252 
253 print("\nPDE is: ")
254 print(my_pde.__str__())
255 print(my_solver)
256 print(my_project)
static double min(double const x, double const y)