Callbacks
TrixiParticles.DensityReinitializationCallback — Type
DensityReinitializationCallback(; interval::Integer=0, dt=0.0)Callback to reinitialize the density field when using ContinuityDensity [70].
Keywords
interval=0: Reinitialize the density everyintervaltime steps.dt: Reinitialize the density in regular intervals ofdtin terms of integration time. This callback does not add extra time steps /tstops; instead, reinitialization is triggered at the first solver step after eachdtinterval has elapsed.reinit_initial_solution: Reinitialize the initial solution (default=true)
TrixiParticles.InfoCallback — Method
InfoCallback()Create and return a callback that prints a human-readable summary of the simulation setup at the beginning of a simulation and then resets the timer. When the returned callback is executed directly, the current timer values are shown.
TrixiParticles.MechanicalWorkCalculatorCallback — Type
MechanicalWorkCalculatorCallback(system::TotalLagrangianSPHSystem, semi; interval=1,
eachparticle=(n_integrated_particles(system) + 1):nparticles(system),
only_compute_force_on_fluid=false)Callback that accumulates the work done by a set of particles in a TotalLagrangianSPHSystem by integrating the instantaneous power over time.
With the default arguments it tracks the work done by the clamped particles that follow a PrescribedMotion. By selecting a different particle set, it can also be used to measure the work done by the structure on the surrounding fluid.
- Prescribed/clamped motion work (default) – monitor only the clamped particles by leaving
eachparticleat its default range(n_integrated_particles(system) + 1):nparticles(system). - Fluid load measurement – set
eachparticle=eachparticle(system)together withonly_compute_force_on_fluid=trueto accumulate the work that the entire structure exerts on the surrounding fluid (useful for drag or lift estimates).
Internally the callback integrates the instantaneous power, i.e. the dot product between the force exerted by the particle and its prescribed velocity, using an explicit Euler time integration scheme.
The accumulated value can be retrieved via calculated_mechanical_work.
Arguments
system: TheTotalLagrangianSPHSystemwhose particles should be monitored.semi: TheSemidiscretizationthat containssystem.
Keywords
interval=1: Interval (in number of time steps) at which to compute the instantaneous power. It is recommended to keep this at1(every time step) or small (≤ 5) to limit time integration errors in the integral.eachparticle=(n_integrated_particles(system) + 1):nparticles(system): Iterator selecting which particles contribute. The default includes all clamped particles in the system; passeachparticle(system)to include every particle.only_compute_force_on_fluid=false: Whentrue, only interactions with fluid systems are accounted for. Combined witheachparticle=eachparticle(system), this accumulates the work that the entire structure exerts on the fluid, which is useful for drag or lift estimates.
Examples
semi = Semidiscretization(system)
ode = semidiscretize(semi, (0.0, 1.0))
# Note that `Semidiscretization` might create a deep copy of the system,
# which means we have to extract the new system from `semi`.
# When working with GPUs, `semidiscretize` also creates a deep copy of `semi` and another
# copy of the system, so the clean way to get the correct new system is this:
semi_new = ode.p.semi
system_new = semi_new.systems[1]
# Create a mechanical work calculator callback that is called every 2 time steps
mechanical_work_cb = MechanicalWorkCalculatorCallback(system_new, semi_new; interval=2)
# After the simulation, retrieve the accumulated mechanical work
mechanical_work = calculated_mechanical_work(mechanical_work_cb)TrixiParticles.calculated_mechanical_work — Method
calculated_mechanical_work(cb::DiscreteCallback{<:Any, <:MechanicalWorkCalculatorCallback})Get the accumulated mechanical work from a MechanicalWorkCalculatorCallback.
Arguments
cb: TheDiscreteCallbackreturned byMechanicalWorkCalculatorCallback.
Examples
# Create a mechanical work calculator callback
mechanical_work_cb = MechanicalWorkCalculatorCallback(system, semi)
# After the simulation, retrieve the accumulated mechanical work
mechanical_work = calculated_mechanical_work(mechanical_work_cb)TrixiParticles.PostprocessCallback — Type
PostprocessCallback(; interval::Integer=0, dt=0.0, exclude_boundary=true, filename="values",
output_directory="out", append_timestamp=false, write_csv=true,
write_json=true, write_file_interval=1, funcs...)Create a callback to post-process simulation data at regular intervals. This callback allows for the execution of a user-defined function func at specified intervals during the simulation. The function is applied to the current state of the simulation, and its results can be saved or used for further analysis. The provided function cannot be anonymous as the function name will be used as part of the name of the value.
The callback can be triggered either by a fixed number of time steps (interval) or by a fixed interval of simulation time (dt).
Keywords
funcs...: Functions to be executed at specified intervals during the simulation. Each function must have the arguments(system, data, t), which will be called for every system, wheredatais a named tuple with fields depending on the system type, andtis the current simulation time. Check the available data for each system withavailable_data(system). See Custom Quantities for a list of pre-defined custom quantities that can be used here. Note: When using GPU backends, all data is automatically transferred to the CPU before being passed to the custom quantity functions. This ensures compatibility but may introduce overhead for frequent callbacks on large simulations.interval=0: Specifies the number of time steps between each invocation of the callback. If set to0, the callback will not be triggered based on time steps. Eitherintervalordtmust be set to something larger than 0.dt=0.0: Specifies the simulation time interval between each invocation of the callback. If set to0.0, the callback will not be triggered based on simulation time. Eitherintervalordtmust be set to something larger than 0.exclude_boundary=true: If set totrue, boundary particles will be excluded from the post-processing.filename="values": The filename of the postprocessing files to be saved.output_directory="out": The path where the results of the post-processing will be saved.write_csv=true: If set totrue, write a csv file.write_json=true: If set totrue, write a json file.append_timestep=false: If set totrue, the current timestamp will be added to the filename.write_file_interval=1: Files will be written after everywrite_file_intervalnumber of postprocessing execution steps. A value of 0 indicates that files are only written at the end of the simulation, eliminating I/O overhead.
Examples
# Create a callback that is triggered every 100 time steps
postprocess_callback = PostprocessCallback(interval=100, example_quantity=kinetic_energy)
# Create a callback that is triggered every 0.1 simulation time units
postprocess_callback = PostprocessCallback(dt=0.1, example_quantity=kinetic_energy)TrixiParticles.SolutionSavingCallback — Type
SolutionSavingCallback(; interval::Integer=0, dt=0.0, save_times=Float64[],
save_initial_solution=true, save_final_solution=true,
output_directory="out", append_timestamp=false, prefix="",
verbose=false, overwrite=false, max_coordinates=2^15,
custom_quantities...)Callback to save the current numerical solution in VTK format. Use at most one of interval, dt, and save_times: pass interval to save every interval accepted time steps, dt to save in intervals of dt in terms of integration time by adding additional tstops (note that this may change the solution), or save_times to save at specific times. The initial and final solution can be added independently with save_initial_solution and save_final_solution.
Additional user-defined quantities can be saved by passing keyword arguments. A custom quantity can be an array or a function. Functions are called as (system, dv_ode, du_ode, v_ode, u_ode, semi, t) when that method exists, otherwise as (system, data, t). In the latter case, data is a named tuple with fields depending on the system type. To ignore a custom quantity for a specific system, return nothing.
Keywords
interval=0: Save the solution everyintervalaccepted time steps. A value of0disables step-interval saves, so only the initial and final solution are saved based onsave_initial_solutionandsave_final_solution, unlesssave_timesordtare used.dt: Save the solution in regular intervals ofdtin terms of integration time by adding additionaltstops(note that this may change the solution).save_times=Float64[]: Specific times at which to save a solution. These times are mutually exclusive withintervalanddt.save_initial_solution=true: Save the initial solution. Setting this tofalsedoes not suppress an initial time explicitly listed insave_times.save_final_solution=true: Save the final solution. Setting this tofalsedoes not suppress a final time explicitly listed insave_times.overwrite=false: Iftrue, previously written VTK files are overwritten instead of creating a new file set at each save interval. In this case, filenames receive the postfix_current. This option is useful for memory efficiency in large simulations where only the final results matter. It provides a rolling checkpoint at each save interval. Iffalse(default), files are not overwritten and an iteration postfix is appended for each interval.output_directory="out": Directory to save the VTK files.append_timestamp=false: Append current timestamp to the output directory.prefix="": Prefix added to the filename.verbose=false: Print to standard IO when a file is written.max_coordinates=2^15: The coordinates of particles will be clipped if their absolute values exceed this threshold.custom_quantities...: Additional custom quantities to include in the VTK output. Check the available data for each system withavailable_data(system). See Custom Quantities for a list of pre-defined custom quantities that can be used here.
Examples
# Save every 100 time steps
saving_callback = SolutionSavingCallback(interval=100)
# Save in intervals of 0.1 in terms of simulation time
saving_callback = SolutionSavingCallback(dt=0.1)
# Additionally store the kinetic energy of each system as "my_custom_quantity"
saving_callback = SolutionSavingCallback(dt=0.1, my_custom_quantity=kinetic_energy)TrixiParticles.SortingCallback — Method
SortingCallback(; interval=-1, dt=0.0, initial_sort=true)Reorders particles according to neighborhood-search cells for performance optimization.
When particles become very unordered throughout a long-running simulation, performance degrades due to increased cache-misses (on CPUs) and lack of block structure (on GPUs). On GPUs, a fully shuffled particle ordering causes a 3-4x slowdown compared to a sorted configuration. On CPUs the performance penalty grows linearly with the problem size and can reach up to a 10x slowdown for very large problems (65M particles). See #1044 for more details.
Keywords
interval: Sort particles at the end of everyintervaltime steps.dt: Sort particles in regular intervals ofdtin terms of integration time. This callback does not add extra time steps /tstops; instead, sorting is triggered at the first solver step after eachdtinterval has elapsed.initial_sort=true: When enabled, particles are sorted at the beginning of the simulation. When the initial configuration is a perfect grid of particles, sorting at the beginning is not necessary and might even slightly slow down the first time steps, since a perfect grid is even better than sorting by NHS cell index.
TrixiParticles.SplitIntegrationCallback — Method
SplitIntegrationCallback(alg; stage_coupling=false, predict_positions=true, kwargs...)Callback to integrate the TotalLagrangianSPHSystems in a Semidiscretization separately from the other systems. For each time step of the main integrator (in which TLSPH systems are ignored), the TLSPH systems are integrated for multiple smaller time steps with their own integrator.
This is useful if the TLSPH systems require much smaller time steps than the fluid systems, which is usually the case when stiff materials are simulated. It is especially useful if additionally the number of TLSPH particles is much smaller than the number of fluid particles, so that a fluid time step is much more expensive than a TLSPH substep.
For fluid-structure interactions with stiff materials like metal or carbon fiber composites, this can lead to significant speedups of several hundred times if the ratio of fluid to solid particles is large enough (e.g. 100:1 or more).
Arguments
alg: The time integration algorithm to use for the TLSPH systems.
Keywords
stage_coupling=false: Iffalse, the TLSPH systems are only updated between full time steps of the main integrator. Iftrue, the TLSPH systems are integrated to the intermediate stage times of the main integrator. The sub-integrator integrates from the previous fluid stage time to the next stage time, using the intermediate stage predictions for the fluid state. This strategy is highly efficient (no sub-steps have to be repeated) but less accurate than repeating the sub-integration with the final (as opposed to predicted) fluid state. Note that this type of stage-level coupling is still more accurate than step-level coupling (stage_coupling=false). For large time step size ratios,stage_coupling=falsemight require a significantly (often 2x) smaller fluid time step size for stability at the FSI interface. For small time step size ratios,stage_coupling=falsemight be sufficiently stable and more efficient thanstage_coupling=true. Note thatstage_coupling=trueis only compatible with fluid time integration schemes that have monotonically increasing stage times and no stage time smaller than the time of the previous full step.predict_positions=true: Iffalse, use the old structure state together with the new fluid state. Iftrue, predict the structure positions for the fluid force calculation. The force on the structure due to the fluid is kept constant during one sub-integration call. When computing this force, the new fluid state and the old structure state are available. To avoid inconsistencies and improve accuracy (not stability), we can predict the structure positions at the new time with a simple Euler step, $u \leftarrow u + v\,(t_{\mathrm{new}} - t_{\mathrm{previous}})$, which is only used for the fluid force calculation.kwargs...: Additional keyword arguments passed to the integrator of the TLSPH systems. Use this for callbacks like theStepsizeCallbackfor choosing the sub-integration time step.
Examples
using OrdinaryDiffEqLowStorageRK
# Low-storage RK method with CFL condition for time step size
callback = SplitIntegrationCallback(CarpenterKennedy2N54(williamson_condition=false),
dt=1.0, # This is overwritten by the stepsize callback
callback=StepsizeCallback(cfl=1.6),
stage_coupling=true)TrixiParticles.SteadyStateReachedCallback — Type
SteadyStateReachedCallback(; interval::Integer=0, dt=0.0,
interval_size::Integer=10, abstol=1.0e-8, reltol=1.0e-6)Terminates the integration when the change of kinetic energy between time steps falls below the threshold specified by abstol + reltol * ekin, where ekin is the total kinetic energy of the simulation.
Keywords
interval=0: Check steady state condition everyintervaltime steps.dt=0.0: Check steady state condition in regular intervals ofdtin terms of integration time by adding additionaltstops(note that this may change the solution).interval_size: The interval in which the change of the kinetic energy is considered.interval_sizeis a (integer) multiple ofintervalordt.abstol: Absolute tolerance.reltol: Relative tolerance.
TrixiParticles.StepsizeCallback — Method
StepsizeCallback(; cfl::Real)Set the time step size according to a CFL condition if the time integration method isn't adaptive itself.
The current implementation is using the simplest form of CFL condition, which chooses a time step size that is constant during the simulation. The step size is therefore only applied once at the beginning of the simulation.
The step size $\Delta t$ is chosen as the minimum
\[ \Delta t = \min(\Delta t_\eta, \Delta t_a, \Delta t_c),\]
where
\[ \Delta t_\eta = 0.125 \, h^2 / \eta, \quad \Delta t_a = 0.25 \sqrt{h / \lVert g \rVert}, \quad \Delta t_c = \text{CFL} \, h / c,\]
with $\nu = \alpha h c / (2n + 4)$, where $\alpha$ is the parameter of the viscosity and $n$ is the number of dimensions.
References
TrixiParticles.UpdateCallback — Method
UpdateCallback(; interval::Integer, dt=0.0)Callback to update quantities either at the end of every interval time steps or in intervals of dt in terms of integration time by adding additional tstops (note that this may change the solution).
Keywords
interval=1: Update quantities at the end of everyintervaltime steps.dt: Update quantities in regular intervals ofdtin terms of integration time by adding additionaltstops(note that this may change the solution).
Custom Quantities
The following pre-defined custom quantities can be used with the SolutionSavingCallback and PostprocessCallback.
TrixiParticles.avg_density — Method
avg_densityReturns the average_density over all particles in a system.
TrixiParticles.avg_pressure — Method
avg_pressureReturns the average pressure over all particles in a system.
TrixiParticles.kinetic_energy — Method
kinetic_energyReturns the total kinetic energy of all particles in a system.
TrixiParticles.max_density — Method
max_densityReturns the maximum density over all particles in a system.
TrixiParticles.max_pressure — Method
max_pressureReturns the maximum pressure over all particles in a system.
TrixiParticles.min_density — Method
min_densityReturns the minimum density over all particles in a system.
TrixiParticles.min_pressure — Method
min_pressureReturns the minimum pressure over all particles in a system.
TrixiParticles.total_mass — Method
total_massReturns the total mass of all particles in a system.