CNAB
Immersa.AbstractCoupler — Type
AbstractCouplerAbstract interface for coupling strategies in the CNAB time integration framework.
This type defines a common interface for different coupler implementations that manage interactions between PDE components or immersed bodies during time integration. Specific couplers include:
NothingCoupler: No coupling required.PrescribedBodyCoupler: For bodies with prescribed motion or known behavior.FsiCoupler: For fluid-structure interaction problems.
Arguments
None.
Returns
An abstract type that serves as a base for all coupling strategies used in CNAB-based simulations.
Immersa.NothingCoupler — Type
NothingCouplerA simple subtype of AbstractCoupler representing the absence of coupling.
Use this type when no body-fluid interaction or other coupling is required in the CNAB time integration framework. It serves as a placeholder that satisfies the coupler interface without modifying the solution.
Arguments
None.
Returns
An instance of NothingCoupler, indicating that no coupling is applied during the simulation.
Immersa.PrescribedBodyCoupler — Type
PrescribedBodyCoupler{M}A subtype of AbstractCoupler for prescribed body motion or constraints.
This coupler stores a field Binv, representing a precomputed operator used to enforce prescribed motion (and forces) on the body. The type M is parametric, allowing flexibility in the data structure used for Binv (e.g., arrays or linear operators).
Arguments
Binv::M: Precomputed operator or matrix used to apply constraints for the prescribed body.
Returns
An instance of PrescribedBodyCoupler suitable for simulations where body motion or behavior is explicitly prescribed.
Immersa.FsiCoupler — Type
FsiCoupler{T,O<:GeometricNonlinearBodyOperators,B}A subtype of AbstractCoupler for fluid–structure interaction (FSI) problems with nonlinear structural dynamics.
This type encapsulates the structural state, geometric nonlinear operators, solver tolerance, BiCGStab solver arguments, and iteration limits required for solving coupled FSI problems using the CNAB time integration framework.
The keyword constructor allows easy setup of the coupler, including automatic initialization of the structural state and operators for a given GeometricNonlinearBody.
Fields
state::StructuralState{T}: Current state of the structural body (displacements, velocities, deformations), parameterized by numeric typeT.ops::O: Operator object representing the geometric nonlinear structural model.tol::T: Numerical tolerance for the iterative solve.bicgstabl_args::B: Arguments for the BiCGStab(ℓ) iterative solver (tuple or named container).maxiter::Int: Maximum iterations during the solver phase.
Arguments (via keyword constructor)
backend::CPU: Computation backend (CPU-based).body::GeometricNonlinearBody{N,T}: Nonlinear structural body withNspatial dimensions and numeric typeT.tol: Solver tolerance (default1e-5).bicgstabl_args: Solver arguments (default(; abstol=T(1e-5), reltol=T(0.0))).maxiter::Int: Maximum iterations (default100).
Returns
A fully initialized FsiCoupler instance ready to couple the fluid and structural solvers in FSI simulations.
Immersa.CNAB — Type
CNAB{N,T,B,U,P,R<:Reg,C<:AbstractCoupler,Au,Aω,Vb,BP<:BodyPoints,A<:ArrayPool,W}Central mutable type representing the state and configuration of a Crank–Nicolson Adams–Bashforth (CNAB) time integration scheme for coupled fluid–structure simulations.
This struct holds all data required for time-stepping the simulation, including fluid and body fields, transform plans, regularization operators, memory pools, and solver buffers. It is designed for high-performance computing with support for GPU/CPU backends and flexible handling of complex bodies and couplers.
Fields
prob::IBProblem{N,T,B,U}: The immersed boundary problem defining the grid and bodies.t0::T: Initial simulation time.i::Int: Current time step index.t::T: Current simulation time.dt::T: Time step size.β::Vector{T}: CNAB scheme coefficients.plan::P: FFT or spectral transform plan.reg::R: Regularizer or interpolation operator.coupler::C: Coupling strategy (FsiCoupler,PrescribedBodyCoupler,NothingCoupler).redist_weights::Au: Redistribution weights for fluid variables.ω::Vector{Aω}: Vorticity field(s).ψ::Vector{Aω}: Streamfunction or auxiliary field(s).u::Vector{Au}: Velocity field(s).f_tilde::Vb,f::Vb: Body force arrays.points::BP: Body point data structure.nonlin::Vector{Vector{Aω}}: Buffers for nonlinear term history.nonlin_count::Int: Counter for nonlinear buffers.ω_bndry::W: Boundary vorticity data.body_pool::A, fluid_pool::A, bndry_pool::A, structure_pool::A: Memory pools to reduce allocations.
Arguments (via constructor)
prob::IBProblem{N,T}: Immersed boundary problem containing grid and body setup.dt: Time step size.t0: Initial simulation time (default0).n_step: Number of previous time steps to retain for CNAB (default2).delta: Regularization kernel (defaultDeltaYang3S()).backend: Computation backend (CPU()or GPU device).coupler_args: Keyword arguments for the coupling constructor (e.g.,FsiCoupler).
Description
The constructor automatically allocates all buffers, precomputes FFT plans, regularization operators, and memory pools, and bundles them into a CNAB object ready for time integration. It performs the following main steps:
- Setup grid and body: retrieves
gridandbodyfromprob. - Pre-allocate main fluid field: creates vorticity arrays.
- Create FFT plan: precomputes spectral transforms for efficient solves.
- Determine problem sizes: computes number of body points and structure variables.
- Allocate memory pools: sizes pools for fluid, body, boundary, and structure arrays.
- Bundle arguments: stores all fields and buffers in a named tuple.
- Build the solution object: calls
initial_solto wrap arguments into a fully initialized CNAB instance.
Returns
A CNAB object fully initialized for coupled time-stepping with the CNAB scheme.
Immersa.initial_sol — Function
initial_sol(backend, body, sol_args, coupler_args)Initialize a CNAB simulation object based on the type of body in the problem.
This function has two methods depending on whether body is a static or geometrically nonlinear (deforming) body:
Static Body Initialization (
AbstractStaticBody)- Constructs a temporary CNAB with a
NothingCoupler. - Initializes body point positions.
- Computes regularization weights.
- Computes the inverse of the body–fluid coupling matrix.
- Creates a
PrescribedBodyCouplerwith the precomputed operator. - Builds the final CNAB object with the coupler.
- Sets simulation time and initializes fluid fields.
- Constructs a temporary CNAB with a
Geometric Nonlinear Body Initialization (
GeometricNonlinearBody)- Constructs an
FsiCouplerfor nonlinear structural dynamics. - Builds the CNAB object with this coupler.
- Sets simulation time and zeros the fluid fields.
- Splits prescribed and deforming points.
- Initializes prescribed body points.
- Updates the structural state and initializes structure operators.
- Computes regularization and redistribution weights.
- Constructs an
Arguments
backend: Computation backend (CPU()or GPU device).body: The body in the problem (AbstractStaticBodyorGeometricNonlinearBody).sol_args: Named tuple with CNAB fields and buffers.coupler_args: Keyword arguments passed to the coupler constructor.
Returns
A fully initialized CNAB object ready for time integration, configured according to the type of body and the specified coupling strategy.
Immersa.zero_vorticity! — Function
zero_vorticity!(sol::CNAB)Reset all fluid-related fields in a CNAB simulation object.
This function sets the vorticity (ω), streamfunction (ψ), and velocity (u) fields to zero across all grid levels. It also resets the nonlinear history counter and re-applies the initial prescribed flow field (u0).
Arguments
sol::CNAB: The CNAB simulation object whose fluid fields are being reset.
Returns
The updated CNAB object with zeroed fluid fields and initial flow re-applied.
Immersa.set_time! — Function
set_time!(sol::CNAB, i::Integer)Advance the CNAB integrator to a specific time step.
This function updates the internal step index (i) and computes the corresponding physical time (t) of the simulation using:
t = t0 + dt * (i - 1)where t0 is the initial simulation time and dt is the time step size. This ensures that all time-dependent operations in the simulation remain consistent.
Arguments
sol::CNAB: The CNAB simulation object to update.i::Integer: The target time step index.
Returns
The updated CNAB object with the new time step and physical time.
Immersa.step! — Function
step!(sol::CNAB)Advance the CNAB simulation by one time step.
This is the main time integration routine that updates both the fluid and structure fields according to the CNAB scheme. A single call to step! performs the following sequence:
- Advance the simulation time step (
set_time!). - Predict the new fluid and body state (
prediction_step!). - Apply fluid–structure coupling (
coupling_step!). - Project the velocity field to enforce incompressibility (
projection_step!). - Update the vorticity field (
apply_vorticity!).
Arguments
sol::CNAB: The CNAB simulation object representing the current state.
Returns
The updated CNAB object after one complete time step.
Immersa.update_reg! — Function
update_reg!(sol::CNAB, body, i)Update the regularization weights for the simulation based on the type of body.
There are two methods:
Static bodies (
AbstractStaticBody)- No update is necessary because the body does not move or deform.
- The function returns
nothing.
Prescribed-motion bodies (
AbstractPrescribedBody)- Updates the regularization weights by calling
update_weights!with the current body point positions. - Ensures that the mapping from body points to the grid reflects the current motion.
- Updates the regularization weights by calling
Arguments
sol::CNAB: CNAB simulation object containing the grid and body fields.body: The body object (AbstractStaticBodyorAbstractPrescribedBody).i: Index or set of points for which the regularization is updated (used for prescribed bodies).
Returns
- Nothing for static bodies.
- Updates
sol.regin-place for prescribed-motion bodies.
Immersa._A_factor — Function
_A_factor(sol::CNAB)Compute the diffusion coefficient used in the CNAB time-stepping scheme.
This coefficient arises in the semi-implicit (Crank–Nicolson) treatment of the viscous term and is given by:
A = Δt / (2 * Re)Arguments
sol::CNAB: CNAB simulation object containing the current state and parameters.
Returns
- Diffusion coefficient (same numeric type as
sol.dt).
Immersa.Ainv — Function
Ainv(sol::CNAB, level)Construct the inverse viscous operator used in the CNAB time-stepping scheme.
Arguments
sol::CNAB: CNAB simulation object containing the problem definition and FFT plans.level: Grid refinement level at which to build the operator.
Returns
EigenbasisTransform: An operator that applies the inverse of(I - aΔ)in spectral space, typically used for implicit diffusion updates within the CNAB integrator.
Immersa.prediction_step! — Function
prediction_step!(sol::CNAB)
prediction_step!(sol::CNAB, level)
prediction_step!(sol::CNAB, level, u_work)Perform the CNAB prediction of the vorticity field.
This function advances the fluid state by computing the predicted vorticity using a semi-implicit Crank–Nicolson treatment for diffusion and an Adams–Bashforth treatment for nonlinear convection. It supports multigrid levels and avoids unnecessary allocations with array pools.
Arguments
sol::CNAB: CNAB simulation object.level(optional): Grid level for single-level update.u_work(optional): Preallocated velocity array for in-place computation.
Returns
- Updated vorticity field in-place within
sol.
Immersa.coupling_step! — Function
coupling_step!(sol::CNAB)Perform the fluid–structure coupling step for the current CNAB time step.
This function dispatches to the appropriate coupling routine based on the solver's coupler. For a prescribed body, it computes the fluid velocity at body points, evaluates the coupling residual, and solves for the correcting body force to enforce velocity constraints.
Arguments
sol::CNAB: CNAB simulation object with the current fluid and body state.
Returns
- Updates
sol.f_tildeand body-related fields in-place.
Immersa.CNAB_Binv_Precomputed — Type
CNABBinvPrecomputed(B)
A precomputed coupling operator for the CNAB solver.
Holds a precomputed matrix B used to solve the body–fluid coupling system directly. Efficient when B is constant (e.g., for rigid or prescribed-motion bodies).
The object is callable like a function to compute the body force f given the desired body velocity u_ib and the CNAB solver sol.
Arguments:
B: Precomputed coupling matrix.f: Body force vector (updated in-place).u_ib: Coupling right-hand side (desired body velocity minus interpolated fluid velocity).sol::CNAB: CNAB solver object (included for signature consistency, not used here).
Returns:
- Updates
fin-place.
Immersa.CNAB_Binv_Iterative — Type
CNAB_Binv_Iterative{T}An iterative coupling operator for the CNAB solver, used when the body–fluid coupling matrix B changes every step (e.g. for moving prescribed bodies).
Instead of precomputing B⁻¹, solves the linear system B f = rhs with BiCGStab(ℓ) at each coupling step. The current contents of f serve as a warm start.
Fields
abstol::T: Absolute solver tolerance (default1e-5).reltol::T: Relative solver tolerance (default0.0).
Call signature
(op::CNAB_Binv_Iterative)(f, rhs, sol::CNAB)Solves B f = rhs in place, where B is assembled from the current geometry via B_rigid_mul!.
Immersa.B_inverse_rigid — Function
B_inverse_rigid(sol::CNAB{N,T,<:AbstractStaticBody})Construct a precomputed coupling operator for a rigid (static) body.
This function builds the body–fluid coupling matrix B and precomputes its inverse via Cholesky factorization. The returned object is a CNAB_Binv_Precomputed, which can be applied during the CNAB coupling step as coupler.Binv(sol.f_tilde, rhs, sol).
- Only for static/non-deforming bodies.
- Precomputing
Bensures fast solves at each timestep. - The matrix is assumed symmetric positive definite (SPD).
Inputs
sol::CNAB: CNAB simulation object containing the body and grid.
Returns
CNAB_Binv_Precomputed: Callable object that efficiently appliesB⁻¹.
Immersa.B_rigid_mul! — Function
B_rigid_mul!(u_ib, f, sol::CNAB{N,T})Apply the rigid-body coupling operator to a force vector.
This function defines the action of the rigid-body coupling matrix B such that u_ib = B * f, where f is a body force distribution and u_ib is the resulting velocity at the immersed boundary points.
Two methods are provided:
- A wrapper that reinterprets flat arrays as vectors of
SVector{N,T}and calls the core implementation. - The main routine, which:
- Regularizes the body forces to the fluid grid.
- Solves for the induced velocity field via the vorticity–streamfunction formulation.
- Interpolates the resulting fluid velocity back to the body points.
This operation is used when assembling the coupling matrix in B_inverse_rigid and represents how the fluid mediates the response of the rigid body to applied forces.
Inputs
u_ib: Output array for body velocities.f: Body force vector.sol::CNAB: CNAB solver containing grid, operators, and regularization data.
Returns
u_ib: The updated body velocity vector after applying the operator.
Immersa.B_deform_mul! — Function
B_deform_mul!(u_ib, f, sol::CNAB)Apply the fluid–structure coupling operator B for a deformable body.
This function maps body forces f to immersed-boundary velocities u_ib, accounting for force spreading, structural response, and velocity interpolation back to the Lagrangian points.
Three methods are provided:
- A converter that reinterprets flat scalar vectors as structured SVector arrays.
- A wrapper that allocates workspace arrays.
- The core routine that computes the coupled fluid–structure response.
Arguments
u_ib: Output array for body velocities (updated in-place).f: Input body force vector.sol::CNAB: CNAB solver object containing grid, operators, and regularization.
Returns
u_ibupdated in-place with the velocity induced byf.
Immersa.f_to_f_tilde! — Function
f_to_f_tilde!(f, sol::CNAB; inverse=false)Convert between the physical body force f and its regularized (spread) form f_tilde used in the fluid solver.
This function rescales the immersed boundary force depending on the direction of conversion:
- When
inverse=false(default), it convertsf_tilde → f, applying the proper scaling for the boundary point spacing and coupling factor. - When
inverse=true, it convertsf → f_tilde, restoring the fluid solver’s representation of the force.
This transformation ensures consistent units and coupling strength between the structure and the fluid solvers.
Notes
The conversion uses:
dt: Time step size.ds: Arc length of immersed boundary points.h: Grid spacing.k = _f_tilde_factor(sol): Coupling-dependent scaling factor.
Arguments
f: Force vector, modified in-place.sol::CNAB: CNAB solver object containing time step, grid, and coupling parameters.inverse: Whether to apply the inverse scaling (f → f_tilde).
Returns
This function returns nothing; the input f is modified in place.
Immersa.redist! — Function
redist!(f, sol::CNAB)Redistribute forces on the immersed boundary to ensure consistency with the fluid.
This function corrects the body forces f after numerical operations by:
- Spreading the force to the fluid grid.
- Applying precomputed redistribution weights.
- Interpolating the corrected forces back to the body points.
Arguments
f: The body force vector (modified in-place).sol::CNAB: The CNAB solver state containing fluid and body information.
Returns
nothing: The inputfis updated in-place.
Immersa.update_redist_weights! — Function
update_redist_weights!(sol::CNAB; tol=1e-10)Compute the redistribution weights used in redist! to ensure consistent transfer of forces between the immersed boundary and the fluid grid.
The weights correct for imbalances caused by spreading forces from body points to the grid, so that later redistribution preserves the physical accuracy of the simulation.
Arguments
sol::CNAB: The CNAB solver object containing the body and fluid state.tol: Minimum threshold for weight inversion to avoid division by zero (default1e-10).
Returns
nothing: The redistribution weights are stored insol.redist_weightsand updated in-place.
Immersa.projection_step! — Function
projection_step!(sol::CNAB)Project the fluid vorticity field to remove the effect of the applied body forces (f_tilde), ensuring that the flow field satisfies the updated constraints after force spreading and redistribution.
Arguments
sol::CNAB: The CNAB solver object containing the fluid and body state.
Effects
- Modifies
sol.ωin-place to account for the applied body forces. - Swaps
sol.ωandsol.ψinternally to reuse memory.
Returns
nothing: The projection modifies the solver state in-place.
Immersa.apply_vorticity! — Function
apply_vorticity!(sol::CNAB)Compute the fluid velocity field from the current vorticity (ω) and update the solution to satisfy boundary conditions and base flow.
Arguments
sol::CNAB: The CNAB solver object containing the fluid and body state.
Effects
- Updates
sol.u(velocity field) and ensuressol.ωsatisfies boundary conditions. - Handles all multigrid levels, applying necessary interpolations between levels.
Returns
nothing: Modifies the solver state in-place.
Immersa.ab_coeffs — Function
ab_coeffs(T, n)Return the Adams-Bashforth coefficients for a given order n.
Arguments
T: Container type to hold the coefficients (e.g., Tuple or Vector).n: Order of the Adams-Bashforth scheme (currently only 1 or 2).
Returns
- A container of type
Twith the AB coefficients:n = 1:[1](forward Euler, AB1)n = 2:[-1//2, 3//2](AB2)
Notes
- AB1 is first-order explicit Euler.
- AB2 is second-order, using current and previous derivative values for better accuracy.
- Only
n=1andn=2are supported; other values throw aDomainError.
Example
ab_coeffs(Tuple, 1) # returns (1,)
ab_coeffs(Tuple, 2) # returns (-1//2, 3//2)Immersa._f_tilde_factor — Function
_f_tilde_factor(sol)Compute the scaling factor used to convert between the physical body force f and the regularized force f_tilde used in the fluid solver.
Arguments
sol: CNAB solver object containing grid and time step information.
Returns
- A scalar factor
k = - h^N / Δtwhere:his the uniform grid spacingNis the spatial dimensionΔtis the time step size- The negative sign follows the solver convention for force transformation
Notes
- This factor is used in
f_to_f_tilde!to scale forces correctly between the immersed boundary and the fluid grid.
Immersa.surface_force! — Function
surface_force!(f, sol)Convert the redistributed force f_tilde back to the physical surface force f.
Arguments
f: Output array that will store the physical surface force.sol: CNAB solver object containingf_tildeand grid/time info.
Behavior
- Computes a scaling factor
k = -h^N / Δtusing_f_tilde_factor(sol). - Applies the formula
f .= -k * sol.f_tildeto recover the actual force on the body surface.
Notes
This reverses the scaling applied in f_to_f_tilde!.
Returns
nothing: The physical surface force is written in-place tof.
Immersa.surface_force_sum — Function
surface_force_sum(sol)Compute the total hydrodynamic force exerted by the fluid on the immersed body.
Arguments
sol: CNAB solver object containingf_tildeand grid/time info.
Behavior
- Computes the scaling factor
k = -h^N / Δtusing_f_tilde_factor(sol). - Sums all entries of
sol.f_tilde(the redistributed force at Lagrangian points). - Scales and flips the sign to recover the physical total force:
total_force = -k * sum(sol.f_tilde).
Returns
total_force: The net physical force vector acting on the body.
Immersa.CNAB_signature — Constant
const CNAB_signatureA compile-time constant used as a unique identifier for the CNAB structure. It stores the string Immersa.jl:CNAB as a vector of bytes (Vector{UInt8}).
This signature can be used, for example, in type-checking, serialization, or validation routines.
Immersa.save — Function
save(io::IO, sol::CNAB)Serialize the current state of a CNAB simulation to a binary I/O stream.
The binary layout (all integers little-endian) is:
CNAB_signature(magic bytes).UInt32scalar size (sizeof(T)).UInt32spatial dimensionN.SVector{N,UInt32}grid cell counts.UInt32number of multigrid levels.Int32current time step index.- Vorticity fields (interior values only, little-endian
T), one block per component per level. UInt32nonlinear history count.- Nonlinear history buffers (same layout as vorticity).
Use load! to restore the state into an existing CNAB object.
Arguments
io::IO: Output stream (e.g. an open file).sol::CNAB: Solver state to serialise.
save(filename::AbstractString, x)Save the state of object x to a file on disk.
This function opens the file specified by filename for writing and delegates the actual saving to a user-defined save method for the object x. It serves as a wrapper to manage file I/O while preserving multiple dispatch.
Arguments
filename::AbstractString: Path to the file to write to.x: Object whose state will be saved.
Returns
- Nothing. The function writes the object's state to disk.
Immersa.load! — Function
load!(io::IO, sol::CNAB)Restore a previously saved CNAB simulation state from a binary I/O stream into an existing solver object.
Reads the binary format produced by save, verifies the magic signature and grid parameters, then overwrites the vorticity, time step, and nonlinear history in sol. The solver is left in a consistent state ready for further time-stepping.
Arguments
io::IO: Input stream positioned at the start of a saved CNAB block.sol::CNAB: Solver object to populate (modified in place).
load!(filename::AbstractString, x)Load the state of object x from a file on disk.
This function opens the file specified by filename and delegates the actual loading to a user-defined load! method for the object x. It acts as a convenient wrapper to handle file I/O while preserving Julia's multiple dispatch semantics.
Arguments
filename::AbstractString: Path to the file to load from.x: Object to populate with the loaded data.
Returns
- The updated object
xwith its state loaded from the file.