7This is a particle tracing simulation for circular bubble dynamics using the Euler equations.
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.
16 file_path, num_particles=10, domain_min=0.1, domain_max=0.9
19 Generates a .dat file with random x- and y-positions,
20 rounding positions to two decimal places.
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.
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))
36 particles.sort(key=
lambda p: p[0])
38 with open(file_path,
"w")
as file:
39 for x, y
in particles:
40 file.write(f
"{x:.2f} {y:.2f}\n")
43 f
"Generated {num_particles} particles in domain [{domain_min}, {domain_max}] and saved to {file_path}"
47parser = exahype2.ArgumentParser(
48 "ExaHyPE 2 - Finite Volumes Particle Tracing Testing Script"
51interpolation_methods = {
60 help=
"|".join(interpolation_methods),
63integration_schemes = {
73 "-integ",
"--integration", default=
"SemiEuler", help=
"|".join(integration_schemes)
78 degrees_of_freedom=128,
82args = parser.parse_args()
86max_h = 1.1 * min(size) / (3.0**args.min_depth)
87min_h = max_h * 3.0 ** (-args.amr_levels)
89project = exahype2.Project(
90 namespace=[
"tests",
"exahype2",
"fv"],
96if args.number_of_snapshots <= 0:
97 time_in_between_plots = 0.0
99 time_in_between_plots = args.end_time / args.number_of_snapshots
100 project.set_output_path(args.output)
102project.set_global_simulation_parameters(
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,
111 args.periodic_boundary_conditions_x,
112 args.periodic_boundary_conditions_y,
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));
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];
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;
137 const auto uSq = u0 * u0 + u1 * u1;
138 const auto u_n = (normal == 0) ? u0 : u1;
140 const auto internalE = Q[Shortcuts::rhoE] - 0.5 * Q[Shortcuts::rho] * uSq;
141 const auto p = (GAMMA - 1.0) * internalE;
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));
151 compute_primitive_variables=compute_primitive_variables
155 {compute_primitive_variables}
157 F[Shortcuts::rho] = Q[Shortcuts::rhoU + normal];
159 F[Shortcuts::rhoU] = Q[Shortcuts::rhoU] * u_n;
160 F[Shortcuts::rhoV] = Q[Shortcuts::rhoV] * u_n;
162 F[Shortcuts::rhoU + normal] += p;
164 F[Shortcuts::rhoE] = (Q[Shortcuts::rhoE] + p) * u_n;
166 compute_primitive_variables=compute_primitive_variables
169fv_solver = exahype2.solvers.fv.godunov.GlobalFixedTimeStep(
171 patch_size=args.degrees_of_freedom,
172 unknowns={
"rho": 1,
"rhoU": 1,
"rhoV": 1,
"rhoE": 1},
173 auxiliary_variables=0,
176 normalised_time_step_size=0.00064,
179fv_solver.set_implementation(
180 initial_conditions=initial_conditions,
181 boundary_conditions=boundary_conditions,
182 max_eigenvalue=max_eigenvalue,
186project.add_solver(fv_solver)
201tracer_particles = fv_solver.add_tracer(
202 name=
"Tracers", particle_attributes=tracer_attributes
206 "InitTracers.dat", num_particles=100, domain_min=0.1, domain_max=0.9
208init_tracers = exahype2.tracer.InsertParticlesFromFile(
209 particle_set=tracer_particles,
210 filename=
"InitTracers.dat",
214init_tracers.descend_invocation_order = 0
215project.add_action_set_to_initialisation(init_tracers)
217tracing_action_set = exahype2.tracer.FiniteVolumesTracingWithForce(
221 integration_scheme=integration_schemes[args.integration],
222 interpolation_scheme=interpolation_methods[args.interpolation],
225tracing_action_set.descend_invocation_order = (
226 fv_solver._action_set_update_patch.descend_invocation_order + 1
229project.add_action_set_to_timestepping(tracing_action_set)
230project.add_action_set_to_initialisation(tracing_action_set)
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.