dragonfly_sim.core.farfield
Non-reflecting far-field refinements on top of the characteristic far field (CompressibleEulerModel.define_farfield_bc).
TransverseFarfield (‘riemann2’) integrates the incoming Riemann invariant’s transverse terms along the boundary, which turns the plain characteristic condition (exact only at normal incidence) into a second-order absorbing one (Engquist-Majda / Higdon) for oblique waves. Unsteady runs only.
Classes
Riemann far-field with transverse terms in the incoming characteristic. |
Module Contents
- class dragonfly_sim.core.farfield.TransverseFarfield(model, farfield_tag, beta=0.5, K=None, relax_length=50.0, relax_sigma=0.25)
Riemann far-field with transverse terms in the incoming characteristic.
At the far field the incoming invariant R- = u.n - 2c/(g-1) obeys (straight boundary, tangent tau = (-n_y, n_x))
dR-/dt + (u.n - c) dR-/dn + u_t dR-/dtau - c du_t/dtau = 0.
Dropping only the normal (incoming-wave) term and keeping beta times the transverse ones, plus a weak relaxation to the freestream, gives
dR-/dt = -beta (u_t dR-/dtau - c du_t/dtau) - K (R- - R-_inf).
beta = 0 with R-(0) = R-_inf is exactly riemann_farfield_state. For linear acoustics on a boundary with tangential mean flow the plane-wave reflection coefficient is
r(theta) = [a(s-1) + beta r^2] / [a(s+1) - beta r^2], s = cos(theta), r = sin(theta), a = 1 + (1-beta) M r,
so beta = 0 gives (s-1)/(s+1), beta = 1 gives (1-s)/(1+s) (no better), and beta = 1/2 gives -((1-s)/(1+s))^2 for any tangential Mach number: the second-order Engquist-Majda/Higdon absorbing condition. K = sigma c_inf (1 - M^2) / L (Poinsot & Lele) only stops long-term drift.
The equation is integrated with the solver’s own BDF coefficients for the deviation delta = R- - R-_inf (a0 + a1 + a2 = 0 cancels R-_inf), with the transverse terms extrapolated from the two previous levels (IMEX/SBDF2; on a BDF1 step T* = T(U^n)):
delta^{n+1} = (-a1 delta^n - a2 delta^{n-1} - dt beta T*) / (a0 + K dt), T* = 2 T(U^n) - T(U^{n-1}).
Explicit is safe here: the far-field cells are coarse (h ~ 1.35), so the transverse transport has CFL ~ U dt/h ~ c dt/h ~ 0.04. Keeping T implicit put gradients of the nonlinear primitives inside the Newton Jacobian, whose form took longer to compile than dolfinx’s JIT wait on the other ranks; this way the residual only sees delta^{n+1} as a stored field and its Jacobian is the plain Riemann one.
T is taken from the interior trace. The levels live in DG fields of the solution degree whose traces on the far-field facets are the boundary data: delta^{n+1} is evaluated at 3 Gauss points per facet and L2-projected (cell-wise least squares; a corner cell’s two facets share its corner dof, so there the trace is a compromise). Storing delta rather than R- keeps the freestream exact: delta stays identically zero for beta = 0.
Usage: construct it, pass it to model.define_farfield_bc(tag, transverse=…), and register it with the model’s TimeIntegrator (attach(integrator)), which then calls prepare() before every physical step’s Newton solve and commit() after the step is accepted. Its two history levels are in functions, for checkpoints.
K defaults to sigma c_inf (1 - M^2) / L with sigma = 0.25 and L the far-field distance relax_length.
Tangential derivatives at p = 0: the state is constant in each cell, so ufl.grad of it vanishes and T would be identically zero (riemann2 would reduce to riemann). The derivatives are therefore taken from a Green-Gauss gradient of the state at the two history levels (core/reconstruction.py): the model’s own reconstruction when it has one (RANS), otherwise a standalone one that is not part of the residual.
- _gradient_into(target)
- _setup_projection(mesh_obj, V_s)
- attach(integrator)
Register with a TimeIntegrator: bind the solution history and receive prepare()/commit() calls from it.
- bind_history(U_n, U_nm1)
- commit()
After the step is accepted (u_vec = U^{n+1}): shift the boundary history.
- prepare(order, ratio=None, dt=None)
Before a step’s Newton solve: delta^{n+1} into delta_next, for a BDF order step of size dt with step ratio dt_n/dt_{n-1}. Collective. Returns max |delta^{n+1}| over the far-field quadrature points.
- transverse_term(U, G=None)
T = u_t dR-/dtau - c du_t/dtau of state U on the far field (UFL), with grad U from the field G (n_state x 2) when given, else ufl.grad.
- R_in
- _coef
- _exprs = None
- _rec = None
- a
- delta_n
- delta_next
- delta_nm1
- dt
- ext_w
- farfield_tag
- functions
- mesh
- model
- n