7This is a convergence test for time integration methods in particle tracing using orbital mechanics.
9This simulation implements the classical one-body problem (particle orbiting a fixed central mass)
10to systematically test the convergence properties and accuracy of different time integration schemes.
11The orbital motion provides an ideal test case because:
13- It has a known analytical solution for circular orbits
14- It tests integration stability over long time periods
15- Orbital energy and angular momentum should be conserved
16- Integration errors accumulate and are easily measurable
18The particle experiences central gravitational force F = GMm/r² and is initialised with exact
19circular orbital conditions. By comparing numerical trajectories against the analytical solution,
22- Order of accuracy for different integration schemes (Euler, RK, Verlet)
23- Long-term stability and energy conservation
24- Phase error accumulation in periodic motion
26This convergence study validates the temporal discretisation accuracy of the particle
27tracing framework for gravitational dynamics.
30parser = exahype2.ArgumentParser(
31 "ExaHyPE 2 - Finite Volumes Particle Tracing Testing Script"
34interpolation_methods = {
40 "-interp",
"--interpolation", default=
"None", help=
"|".join(interpolation_methods)
43integration_schemes = {
53 "-integ",
"--integration", default=
"Euler", help=
"|".join(integration_schemes)
58 degrees_of_freedom=64,
62args = parser.parse_args()
66max_h = 1.1 * min(size) / (3.0**args.min_depth)
67min_h = max_h * 3.0 ** (-args.amr_levels)
69project = exahype2.Project(
70 namespace=[
"tests",
"exahype2",
"fv"],
76if args.number_of_snapshots <= 0:
77 time_in_between_plots = 0.0
79 time_in_between_plots = args.end_time / args.number_of_snapshots
80 project.set_output_path(args.output)
82project.set_global_simulation_parameters(
86 min_end_time=args.end_time,
87 max_end_time=args.end_time,
88 first_plot_time_stamp=0.0,
89 time_in_between_plots=time_in_between_plots,
91 args.periodic_boundary_conditions_x,
92 args.periodic_boundary_conditions_y,
96initial_conditions =
"""
97 for (int i = 0; i < NumberOfUnknowns + NumberOfAuxiliaryVariables; i++) {
102boundary_conditions =
"""
103 for (int i = 0; i < NumberOfUnknowns + NumberOfAuxiliaryVariables; i++) {
104 Qoutside[i] = Qinside[i];
109 for (int i = 0; i < NumberOfUnknowns; i++) {
118analytical_solution =
"""
119 // Analytical solution for one-body problem with fixed central mass (circular orbit)
121 constexpr double mu = 10.0; // Gravitational parameter (G*M)
123 // Fixed central body position (Domain center)
124 constexpr double x_center = 1.5;
125 constexpr double y_center = 1.5;
127 // Initial position of orbiting body
128 constexpr double x0 = 2.0;
129 constexpr double y0 = 2.0;
131 // Initial velocity of orbiting body (circular orbit)
132 const double r = sqrt(pow(x0 - x_center, 2) + pow(y0 - y_center, 2));
133 const double omega = sqrt(mu / (r * r * r));
135 // Compute velocity perpendicular to radius for circular orbit
136 const double vx0 = -omega * (y0 - y_center); // Perpendicular direction (tangential)
137 const double vy0 = omega * (x0 - x_center);
139 // Mass of orbiting body
140 const double mass = 1.0;
142 // Time-dependent angle
143 const double angle = atan2(y0 - y_center, x0 - x_center) + omega * t;
146 solution[0] = x_center + r * cos(angle); // x
147 solution[1] = y_center + r * sin(angle); // y
149 // Velocity (perpendicular to radius)
150 solution[5] = -r * omega * sin(angle); // vx
151 solution[6] = r * omega * cos(angle); // vy
153 // Acceleration (central)
154 solution[7] = -mu / (r * r * r) * (solution[0] - x_center); // ax
155 solution[8] = -mu / (r * r * r) * (solution[1] - y_center); // ay
158 solution[2] = 0.0; // rho (density)
159 solution[3] = 0.0; // fluid_u
160 solution[4] = 0.0; // fluid_v
161 solution[9] = mass; // m (mass)
164fv_solver = exahype2.solvers.fv.godunov.GlobalFixedTimeStep(
166 patch_size=args.degrees_of_freedom,
168 auxiliary_variables=0,
171 normalised_time_step_size=0.0025,
174fv_solver.set_implementation(
175 initial_conditions=initial_conditions,
176 boundary_conditions=boundary_conditions,
177 max_eigenvalue=max_eigenvalue,
181project.add_solver(fv_solver)
196tracer_particles = fv_solver.add_tracer(
197 name=
"Tracers", particle_attributes=tracer_attributes
200init_tracers = exahype2.tracer.InsertParticlesByCoordinatesAndData(
201 particle_set=tracer_particles,
202 unknowns_per_particle=len(tracer_attributes[
"unknowns"]),
204 {2.0, 2.0, 0.0, 0.0, 0.0, -2.65914794847249380538e+00, 2.65914794847249424947e+00, -1.41421356237309474579e+01, -1.41421356237309474579e+01, 1.0}
208init_tracers.descend_invocation_order = 0
209project.add_action_set_to_initialisation(init_tracers)
211tracing_action_set = exahype2.tracer.FiniteVolumesTracingWithForce(
215 integration_scheme=integration_schemes[args.integration],
217 interpolation_scheme=interpolation_methods[args.interpolation],
220tracing_action_set.descend_invocation_order = (
221 fv_solver._action_set_update_patch.descend_invocation_order + 1
224project.add_action_set_to_timestepping(tracing_action_set)
225project.add_action_set_to_initialisation(tracing_action_set)
227from pathlib
import Path
229error_measurement = exahype2.solvers.fv.ErrorMeasurementParticles(
231 error_measurement_implementation=analytical_solution,
232 output_file_name=args.output +
"/Error_" + Path(__file__).name,
233 particle_set=tracer_particles,
234 descend_invocation_order=65536,
237project.set_load_balancer(
"new ::exahype2::LoadBalancingConfiguration")
238project.set_build_mode(mode=peano4.output.string_to_mode(args.build_mode))
239project = project.generate_Peano4_project(verbose=
False)
240project.build(make=
True, make_clean_first=
True, throw_away_data_after_build=
True)