Peano
Loading...
Searching...
No Matches
fv-tracers-circular-bubble.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 peano4
4import exahype2
5
6"""
7This is a particle tracing simulation for circular bubble dynamics using the Euler equations.
8
9In this one-way coupling setup, the fluid field (circular pressure bubble) affects the particles' motion,
10but the particles do not influence the fluid dynamics. The simulation models particle transport
11through a circular high-pressure region.
12"""
13
14
16 file_path, num_particles=10, domain_min=0.1, domain_max=0.9
17):
18 """
19 Generates a .dat file with random x- and y-positions,
20 rounding positions to two decimal places.
21
22 Parameters:
23 file_path (str): Path to save the .dat file.
24 num_particles (int): Number of particles to generate.
25 domain_min (float): Minimum bound of the domain.
26 domain_max (float): Maximum bound of the domain.
27 """
28 particles = []
29 import random
30
31 for _ in range(num_particles):
32 x = round(random.uniform(domain_min, domain_max), 2)
33 y = round(random.uniform(domain_min, domain_max), 2)
34 particles.append((x, y))
35
36 particles.sort(key=lambda p: p[0])
37
38 with open(file_path, "w") as file:
39 for x, y in particles:
40 file.write(f"{x:.2f} {y:.2f}\n")
41
42 print(
43 f"Generated {num_particles} particles in domain [{domain_min}, {domain_max}] and saved to {file_path}"
44 )
45
46
47parser = exahype2.ArgumentParser(
48 "ExaHyPE 2 - Finite Volumes Particle Tracing Testing Script"
49)
50
51interpolation_methods = {
52 "None": 0, # No interpolation (use raw values)
53 "Constant": 1, # Piecewise constant interpolation (nearest neighbor)
54 "Linear": 2, # Piecewise linear interpolation (more accurate)
55}
56parser.add_argument(
57 "-interp",
58 "--interpolation",
59 default="Constant",
60 help="|".join(interpolation_methods),
61)
62
63integration_schemes = {
64 "Static": 0, # No integration (static particles)
65 "Euler": 1, # Explicit Euler method (simple but less accurate)
66 "SemiEuler": 2, # Semi-implicit Euler method (better stability)
67 "Verlet": 3, # Velocity Verlet algorithm (good for orbital mechanics)
68 "Midpoint": 4, # Midpoint method (2nd order Runge-Kutta)
69 "RK3": 5, # 3rd order Runge-Kutta method (high accuracy)
70 "RK4": 6, # 4th order Runge-Kutta method (higher accuracy)
71}
72parser.add_argument(
73 "-integ", "--integration", default="SemiEuler", help="|".join(integration_schemes)
74)
75
76parser.set_defaults(
77 min_depth=3,
78 degrees_of_freedom=128,
79 end_time=1.0,
80)
81
82args = parser.parse_args()
83
84size = [1.0, 1.0]
85offset = [0.0, 0.0]
86max_h = 1.1 * min(size) / (3.0**args.min_depth)
87min_h = max_h * 3.0 ** (-args.amr_levels)
88
89project = exahype2.Project(
90 namespace=["tests", "exahype2", "fv"],
91 project_name=".",
92 directory=".",
93 executable="ExaHyPE",
94)
95
96if args.number_of_snapshots <= 0:
97 time_in_between_plots = 0.0
98else:
99 time_in_between_plots = args.end_time / args.number_of_snapshots
100 project.set_output_path(args.output)
101
102project.set_global_simulation_parameters(
103 dimensions=2,
104 size=size,
105 offset=offset,
106 min_end_time=args.end_time,
107 max_end_time=args.end_time,
108 first_plot_time_stamp=0.0,
109 time_in_between_plots=time_in_between_plots,
110 periodic_BC=[
111 args.periodic_boundary_conditions_x,
112 args.periodic_boundary_conditions_y,
113 ],
114)
115
116initial_conditions = """
117 Q[Shortcuts::rho] = 1.0;
118 Q[Shortcuts::rhoU] = 0.0;
119 Q[Shortcuts::rhoV] = 0.0;
120 // Circular bubble centered at (0.5, 0.5) with radius 0.2
121 Q[Shortcuts::rhoE] = ((std::sqrt(std::pow(0.5 - x(0), 2) + std::pow(0.5 - x(1), 2)) < 0.2) ? (1.1) : (1.0));
122"""
123
124boundary_conditions = """
125 // Reflective boundary conditions
126 Qoutside[Shortcuts::rho] = Qinside[Shortcuts::rho];
127 Qoutside[Shortcuts::rhoU] = -Qinside[Shortcuts::rhoU];
128 Qoutside[Shortcuts::rhoV] = -Qinside[Shortcuts::rhoV];
129 Qoutside[Shortcuts::rhoE] = Qinside[Shortcuts::rhoE];
130"""
131
132compute_primitive_variables = r"""
133 const auto irho = 1.0 / Q[Shortcuts::rho];
134 const auto u0 = Q[Shortcuts::rhoU] * irho;
135 const auto u1 = Q[Shortcuts::rhoV] * irho;
136
137 const auto uSq = u0 * u0 + u1 * u1;
138 const auto u_n = (normal == 0) ? u0 : u1;
139
140 const auto internalE = Q[Shortcuts::rhoE] - 0.5 * Q[Shortcuts::rho] * uSq;
141 const auto p = (GAMMA - 1.0) * internalE;
142"""
143
144max_eigenvalue = r"""
145 {compute_primitive_variables}
146 const auto speedOfSound = std::sqrt(GAMMA * p * irho);
147 auto result = std::fmax(0.0, std::fabs(u_n - speedOfSound));
148 result = std::fmax(result, std::fabs(u_n + speedOfSound));
149 return result;
150""".format(
151 compute_primitive_variables=compute_primitive_variables
152)
153
154flux = r"""
155 {compute_primitive_variables}
156
157 F[Shortcuts::rho] = Q[Shortcuts::rhoU + normal];
158
159 F[Shortcuts::rhoU] = Q[Shortcuts::rhoU] * u_n;
160 F[Shortcuts::rhoV] = Q[Shortcuts::rhoV] * u_n;
161
162 F[Shortcuts::rhoU + normal] += p;
163
164 F[Shortcuts::rhoE] = (Q[Shortcuts::rhoE] + p) * u_n;
165""".format(
166 compute_primitive_variables=compute_primitive_variables
167)
168
169fv_solver = exahype2.solvers.fv.godunov.GlobalFixedTimeStep(
170 name="FVSolver",
171 patch_size=args.degrees_of_freedom,
172 unknowns={"rho": 1, "rhoU": 1, "rhoV": 1, "rhoE": 1},
173 auxiliary_variables=0,
174 min_volume_h=min_h,
175 max_volume_h=max_h,
176 normalised_time_step_size=0.00064,
177)
178
179fv_solver.set_implementation(
180 initial_conditions=initial_conditions,
181 boundary_conditions=boundary_conditions,
182 max_eigenvalue=max_eigenvalue,
183 flux=flux,
184)
185
186project.add_solver(fv_solver)
187
188tracer_attributes = {
189 "unknowns": {
190 "rho": 1,
191 "fluid_u": 1,
192 "fluid_v": 1,
193 "u": 1,
194 "v": 1,
195 "a_x": 1,
196 "a_y": 1,
197 "d": 1,
198 }
199}
200
201tracer_particles = fv_solver.add_tracer(
202 name="Tracers", particle_attributes=tracer_attributes
203)
204
206 "InitTracers.dat", num_particles=100, domain_min=0.1, domain_max=0.9
207)
208init_tracers = exahype2.tracer.InsertParticlesFromFile(
209 particle_set=tracer_particles,
210 filename="InitTracers.dat",
211 scale_factor=1.0,
212)
213
214init_tracers.descend_invocation_order = 0
215project.add_action_set_to_initialisation(init_tracers)
216
217tracing_action_set = exahype2.tracer.FiniteVolumesTracingWithForce(
218 tracer_particles,
219 fv_solver,
220 project,
221 integration_scheme=integration_schemes[args.integration],
222 interpolation_scheme=interpolation_methods[args.interpolation],
223)
224
225tracing_action_set.descend_invocation_order = (
226 fv_solver._action_set_update_patch.descend_invocation_order + 1
227)
228
229project.add_action_set_to_timestepping(tracing_action_set)
230project.add_action_set_to_initialisation(tracing_action_set)
231
232project.set_load_balancer("new ::exahype2::LoadBalancingConfiguration")
233project.set_build_mode(mode=peano4.output.string_to_mode(args.build_mode))
234project = project.generate_Peano4_project(verbose=False)
235project.output.makefile.add_CXX_flag("-DGAMMA=1.4")
236project.build(make=True, make_clean_first=True, throw_away_data_after_build=True)
generate_random_particles(file_path, num_particles=10, domain_min=0.1, domain_max=0.9)
Generates a .dat file with random x- and y-positions, rounding positions to two decimal places.