Patch¶
Patch classes for specifying boundary conditions on structured blocks.
Limiting index rules¶
Patches are defined by specifying which block face or part of a face they are
on. Every Patch subclass is constructed as:
PatchType(i=..., j=..., k=..., label=...)
taking one argument for each of the three indexing directions i, j,
and k, subject to the following rules:
The first point in a direction is indexed 0; negative indices wrap around such that -1 is the last point.
Indices are inclusive, so
i=(0,-1)spans the entire range oficoordinate.Integer arguments are interpreted as a constant value of that index:
i=0means the patch spans the first i face;j=-1means the patch spans the last j face. Integer arguments are shorthand for, e.g.i=(0,0).Patches must be 2D subsets of an external face of the block. This implies that at least one constant dimension must be specified with a value 0 or -1.
Omitting a direction argument implies the patch should include every point in that direction, and is shorthand for e.g.
j=(0, -1).The elements of a direction tuple should be in ascending order after negative indices are wrapped.
k=(6,4)is not valid, and neither isk=(-1, -2).
Types of patches¶
The different types of patches (e.g. periodic, inlet, outlet) are represented
by subclasses of the abstract base class Patch,
but are all initialised by passing in the limiting indices and an optional
label for later debugging. Storing boundary condition information or matching
connections between patches is handled by methods on the subclasses.
Storage and attachment to blocks¶
A patch can be constructed in isolation without a Block.
However, any property that depends on block geometry – resolving negative
indices to absolute coordinates, computing patch size, or accessing block
coordinate views – will raise an error until the patch is attached to a block.
Patches are stored in a BlockPatchCollection accessible at block.patches.
Adding a patch to this collection automatically attaches it to the block,
validates its limits against the block shape, and checks that it does not
spatially overlap with any existing patch of the same type on the same face.
The collection supports retrieval by integer index, by string label, and by
patch type:
p = block.patches[0] # by index
p = block.patches["inlet_hub"] # by label
ps = block.patches.inlet # list of all InletPatch objects
The type-grouped properties (inlet, outlet, periodic,
rotating, etc.) each return a plain list.
Mutation is through the standard collection interface: append, extend,
insert, and del:
block.patches.append(InletPatch(i=0, label="inlet_hub"))
del block.patches["inlet_hub"]
len() returns the number of patches on the block.
A GridPatchCollection at grid.patches provides a corresponding
read-only aggregate view across all blocks in a
Grid. It supports integer indexing, slicing,
iteration, len(), and the same type-grouped properties (e.g.
grid.patches.periodic), but does not support string-key access or any
mutation methods.
Examples
# example: patch_examples
import numpy as np
import ember.patch
from ember.block import Block
from ember.fluid import PerfectFluid
# Build a block with axial (x), radial (r), and circumferential (t) coordinates.
fluid = PerfectFluid(cp=1005.0, gamma=1.4, mu=1.8e-5, Pr=0.7)
block = Block(shape=(4, 5, 6))
block.set_fluid(fluid)
block.set_x(np.linspace(0.0, 1.0, 4).reshape(-1, 1, 1) * np.ones((4, 5, 6)))
block.set_r(np.linspace(0.5, 1.0, 5).reshape(1, -1, 1) * np.ones((4, 5, 6)))
block.set_t(np.linspace(0.0, 0.5, 6).reshape(1, 1, -1) * np.ones((4, 5, 6)))
# Add inlet, outlet, and periodic patches; appending attaches each to the block.
inlet = ember.patch.InletPatch(i=0, label="inflow")
outlet = ember.patch.OutletPatch(i=-1, label="outflow")
block.patches.extend([inlet, outlet])
block.patches.extend([
ember.patch.PeriodicPatch(k=0, label="lower"),
ember.patch.PeriodicPatch(k=-1, label="upper"),
])
print(len(block.patches)) # 4
print(len(block.patches.periodic)) # 2
# Patch shape and size are resolved against the block once attached.
# shape is (1, 5, 6): one i-plane, full j and k extent.
print(inlet.size) # 30
print(inlet.shape) # (1, 5, 6)
# const_dim is the index of the constant face (0=i, 1=j, 2=k).
print(inlet.const_dim) # 0
print(block.patches["lower"].const_dim) # 2
# Negative indices are stored as-is and resolved to absolute coordinates on demand.
# i=(1,-2), k=(1,-2) on shape (4,5,6): i=-2 resolves to 2, k=-2 resolves to 4.
partial = ember.patch.InviscidPatch(j=-1, i=(1, -2), k=(1, -2), label="tip_partial")
block.patches.append(partial)
print(partial.ijk_lim_abs[0, 1]) # 2
print(partial.ijk_lim_abs[2, 1]) # 4
print(partial.shape) # (2, 1, 4)
# Use the patch slice to index block coordinate arrays directly.
print(block[inlet.slice].x.shape) # (1, 5, 6)
print(block.xrt[inlet.slice].shape) # (1, 5, 6, 3)
# Set inlet stagnation conditions; values can be scalars or arrays
# that broadcast to the patch shape.
inlet.set_Po_To_Alpha_Beta(Po=2e5, To=1200.0, Alpha=0.0, Beta=0.0)
print(inlet.Po) # 200000.0
print(inlet.To) # 1200.0
nj, nk = inlet.shape[1], inlet.shape[2]
Po_array = np.linspace(1.8e5, 2.2e5, nj * nk).reshape(1, nj, nk)
inlet.set_Po_To_Alpha_Beta(Po=Po_array)
print(inlet.Po.shape) # (1, 5, 6)
# Set static pressure on the outlet, or attach a mass-flow PID throttle.
outlet.set_P(1e5)
print(outlet.P) # 100000.0
outlet.set_throttle(mdot_target=3.0, K_pid=(1.0, 0.1, 0.0))
# Set angular velocity on a rotating wall patch.
rot_patch = ember.patch.RotatingPatch(j=0, label="hub")
block.patches.append(rot_patch)
rot_patch.set_Omega(500.0)
print(rot_patch.rpm) # 4774.648
Base classes¶
- class ember.basepatch.Patch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
ABCInitialize with start and end indices for each dimension.
Indices are inclusive and a single integer sets a constant value in that dimension. See
ember.patchfor the full index rules.- Parameters:
- set_i_lim(i)[source]¶
Set the start and end indices on the i dimension.
Indices are inclusive and a single integer sets a constant value in that dimension. See
ember.patchfor the full index rules.
- set_j_lim(j)[source]¶
Set the start and end indices on the j dimension.
Indices are inclusive and a single integer is shorthand for a constant face, e.g.
j=0is equivalent toj=(0, 0). Seeember.patchfor the full index rules.
- set_k_lim(k)[source]¶
Set the start and end indices on the k dimension.
Indices are inclusive and a single integer is shorthand for a constant face, e.g.
k=0is equivalent tok=(0, 0). Seeember.patchfor the full index rules.
- get_ijk_face(perm=(0, 1, 2), flip=())[source]¶
Block indices for faces on the patch.
For example the constant k face bounded by (i -> i+1) and (j -> j+1) has indices (i, j, k).
- attach_to_block(block)[source]¶
Attach this patch to a block and validate limits against block shape.
Do not call directly; attachment is handled automatically when a patch is added to
patchesviaBlockPatchCollection.- Parameters:
block (
Block) – The block this patch belongs to. A weak reference is stored.
- check_match(other, rtol=1e-06)[source]¶
Check if this patch matches another patch for pairing purposes.
Base implementation always returns None. Subclasses should override this method to implement their specific matching criteria.
- copy()[source]¶
Return a new unattached patch of the same type with the same limits, label, and boundary condition state.
The returned patch is fully independent: it shares no mutable state with the original and is not attached to any block. Attach it to a block via
block.patches.append(copy)before using geometry-dependent properties.Boundary condition parameters (e.g. stagnation conditions on an inlet, static pressure on an outlet) are copied; any cached solver state that depends on block geometry is not.
- property block¶
Access the parent block this patch is attached to.
- property block_view¶
Sliced view of the parent block at this patch location;
Blockwith shapeshape.Equivalent to
block[patch.slice]. Cached atattach_to_block()to avoid repeated sliced Block creation overhead.
- property block_view_offset_1¶
Sliced view one layer interior to the patch face;
Blockwith shapeshape.Used to read the outgoing characteristic state (e.g. entropy at a subsonic outlet) from the first interior layer. Equivalent to
block[patch.slice]offset by one along the constant dimension. Cached atattach_to_block()to avoid repeated sliced Block creation overhead.
- property block_view_offset_2¶
Sliced view two layers interior to the patch face;
Blockwith shapeshape.Used together with
block_view_offset_1to linearly (two-point) extrapolate the outgoing characteristic state to the boundary face,X_face = 2 * X_1 - X_2. Equivalent toblock[patch.slice]offset by two along the constant dimension. Cached atattach_to_block()to avoid repeated sliced Block creation overhead.
- property const_dim¶
Axis of the constant dimension;
intin{0, 1, 2}.
- property ien¶
End index in the i dimension;
int.
- property ijk_lim_abs¶
Limits with negative indices resolved to positive;
ndarrayof shape(3, 2).
- property ist¶
Start index in the i dimension;
int.
- property jen¶
End index in the j dimension;
int.
- property jst¶
Start index in the j dimension;
int.
- property ken¶
End index in the k dimension;
int.
- property kst¶
Start index in the k dimension;
int.
- property label¶
String identifier for the patch;
strorNone.
- property shape¶
Extent of the patch in each dimension as
(ni, nj, nk); the constant dimension is always 1.
- property slice¶
tupleofsliceobjects for indexing the parent block array.
- property xrt_centre¶
Centre coordinates of the patch as
(x, r, t);ndarrayof shape(3,).
- class ember.basepatch.RevolutionPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
PatchPatch on a surface of revolution.
Intermediate base class for patches that require surface-of-revolution geometry (inlet, outlet, mixing). A surface of revolution is an annular or axisymmetric surface where one patch axis is purely circumferential (the pitch direction, along which only theta varies) and the other runs meridionally from hub to tip (the span direction, along which both x and r vary).
When a patch is added to a block via
patches,attach_to_block()automatically identifies the span and pitch axes from the block geometry. It raisesValueErrorif the geometry is not a surface of revolution (i.e. a pitch axis with constant x and r cannot be found).The key operation provided by this class is pitch-averaging: computing a circumferentially averaged flow state that subclasses (inlet, outlet, mixing) use to apply boundary conditions.
- set_block_avg()[source]¶
Compute pitch-averaged conserved variables and store in block_avg.
Uses node-based pitch weights to compute a weighted sum of
block_view.conserved_ndover the pitch dimension, writing the result directly intoself.block_avg.conserved_nd.
- attach_to_block(block)[source]¶
Attach to block and detect surface-of-revolution geometry.
Calls the base Patch attach, then determines span/pitch dimensions and computes meridional properties. Raises ValueError if the patch is not a surface of revolution.
- resolve_from_interface()[source]¶
Rotate block_view momentum in-place from (norm, span) to (x, r) coordinates.
Inverse of
resolve_to_interface:rhoV_norm -> rhoVx = cosxi * rhoV_norm - sinxi * rhoV_span rhoV_span -> rhoVr = sinxi * rhoV_norm + cosxi * rhoV_span
- resolve_to_interface()[source]¶
Rotate block_view momentum in-place from (x, r) to (norm, span) coordinates.
Modifies
block_view.conservedso that the axial and radial momentum components become the interface-normal and interface-span components:rhoVx -> rhoV_norm = cosxi * rhoVx + sinxi * rhoVr rhoVr -> rhoV_span = -sinxi * rhoVx + cosxi * rhoVr
Uses the pre-computed rotation matrix
_rot_tobroadcast alongspan_dimto match the full block shape.
- smooth_pitch_121(field, alpha)[source]¶
Apply a periodic 1-2-1 smoothing pass along the pitch axis.
Returns
alpha * smoothed + (1 - alpha) * fieldwheresmoothedis one pass of the discrete 1-2-1 filterf[i] = (f[i-1] + 2*f[i] + f[i+1]) / 4with periodic wrap alongpitch_dim. The pitch direction is circumferential, so periodic wrap is exact for an annular passage.The 1-2-1 filter has amplification \(\cos^2(k\Delta/2)\): it preserves the pitch mean and smooth variation, and annihilates the Nyquist (sawtooth) mode. Blending with the unsmoothed field by
alphatunes the strength:alpha=1is a full 1-2-1 pass,alpha=0leaves the field unchanged.
- property block_avg¶
Pitch-averaged flow field;
Blockof shape(nspan,).Coordinates are the pitch-mean x, r, t at each span station. The conserved variables are populated by calling
set_block_avg(); before that call the flow-field arrays contain uninitialised values.
- property pitch_dim¶
Axis of the pitchwise (circumferential) dimension;
intin{0, 1, 2}.Detected automatically from block geometry on
attach_to_block(): the axis along which only theta varies while x and r remain constant.
- property span_dim¶
Axis of the spanwise (meridional) dimension;
intin{0, 1, 2}.Detected automatically from block geometry on
attach_to_block(): the axis along which x and r vary (hub to tip).
- property spf¶
Span fraction at each node, normalised to
[0, 1]by meridional arc-length;ndarrayof shape(nspan,).spf[0] == 0.0at the hub/start corner andspf[-1] == 1.0at the tip/end corner. Spacing reflects the actual meridional distances between nodes, not their indices.
Concrete patch types¶
- class ember.periodic.PeriodicPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
PatchConnected boundary to another block.
This applies to patches which are exactly coincident, and patches which are periodic in the circumferential direction of an annular domain. The patches should come in pairs, and connectivity between the two patches is detected automatically. The conserved variables on the two patches are averaged at each time step to enforce periodicity.
- class ember.inlet.InletPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
RevolutionPatchInflow boundary condition.
Enforces prescribed stagnation pressure \(p_0\), stagnation temperature \(T_0\), yaw angle \(\alpha\), and pitch angle \(\beta\) at the face. Stagnation enthalpy and entropy are derived from \(p_0\) and \(T_0\) and imposed directly. Flow direction is set from \(\alpha\) and \(\beta\).
Static pressure is not imposed directly. Each call to
apply()relaxes \(p_\mathrm{soln}\) toward the static pressure at the first interior node, then clamps it below the stagnation pressure. This damps acoustic transients at startup without prescribing a fixed pressure. Callupdate_soln()once per timestep (before the Runge-Kutta stages) to advance \(p_\mathrm{soln}\).All four boundary condition values must be set via
set_Po_To_Alpha_Beta()beforeapply()is called.- set_Po_To_Alpha_Beta(Po=None, To=None, Alpha=None, Beta=None)[source]¶
Set inlet boundary condition values.
Each argument is independent; omitted arguments retain their current value. All four must be set before
apply()can be called. Stagnation pressure and stagnation temperature must be positive and finite. Yaw and pitch angles are in degrees. Each value accepts a scalar or an array that broadcasts toshape.
- apply()[source]¶
Impose inlet boundary conditions on the patch.
Stagnation enthalpy, entropy, and trigonometric flow-direction factors derived from
Po,To,Alpha, andBetaare cached on the first call and combined with a relaxed static pressure to reconstruct the velocity vector, which is stored viaset_rho_u_Vxrt_nd().Static pressure is not prescribed; instead it is relaxed from the previous-step solution toward the static pressure at the first interior node (a Multall-style pressure extrapolation):
\[p_\mathrm{new} = p_\mathrm{soln} + rf\,(p_\mathrm{interior} - p_\mathrm{soln})\]using the relaxation factor
rf, then clamped below the stagnation pressurePo. The solution reference is advanced by callingupdate_soln()once per timestep.rfis used directly as a convex weight (no Mach scaling); higher values converge faster but may excite acoustics.- Raises:
ValueError – If the incoming solution has a negative axial velocity at any inlet boundary node (backflow), the calculation is ill-posed and is stopped rather than continued into an unphysical state.
- class ember.outlet.OutletPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
RevolutionPatchOutflow boundary condition.
Enforces a prescribed static pressure \(p\) at the face. Entropy and all three velocity components are linearly (two-point) extrapolated from the first two interior layers,
X_face = 2 * X_1 - X_2, so the outgoing entropy and vorticity characteristics are carried to the boundary with their interior gradient.Three optional features extend the constant uniform pressure condition:
Throttle
set_throttle(): a PID controller adjusts the pressure each step to drive the patch mass flow toward a target value.Spanwise adjustment
set_adjustment(): adds zero-mean radial equilibrium and dynamic head profiles to the uniform pressure target.Backflow handling
set_backflow(): when reversed flow is detected, affected nodes are treated as inlets; seeInletPatchfor the density relaxation scheme.
Static pressure must be set via
set_P()beforeapply()is called.- set_adjustment(K_dyn=0.0, radial_equilibrium=True, rf=0.1)[source]¶
Configure nonuniform adjustments to outlet pressure.
The pressure at each node is:
\[p = p_\mathrm{out} + \Delta p_\mathrm{throttle} + \Delta p_\mathrm{nonunif}\]\(\Delta p_\mathrm{nonunif} = \Delta p_\mathrm{dyn} + \Delta p_\mathrm{swirl}\) is computed from the boundary solution each step and the total nonuniformity is relaxed toward the new value:
\[\Delta p_\mathrm{nonunif}^\mathrm{new} = \mathit{rf} \, \Delta p_\mathrm{nonunif} + (1 - \mathit{rf}) \, \Delta p_\mathrm{nonunif}^\mathrm{old}\]\(\overline{\Box}\) denotes the area-weighted mean. When
radial_equilibrium=Trueit is the pitch mean at each spanwise location, preserving spanwise variation; whenradial_equilibrium=Falseit is the annulus mean.Dynamic head offset \(\Delta p_\mathrm{dyn}\):
Mimics a physical gauze or screen to suppress backflow by driving the exit velocity toward a more uniform profile. \(\tfrac{1}{2}\rho V_m^2\) is the meridional dynamic head. The offset has zero net area average by construction:
\[\Delta p_\mathrm{dyn} = K_\mathrm{dyn} \left(\tfrac{1}{2}\rho V_m^2 - \overline{\tfrac{1}{2}\rho V_m^2}\right)\]Swirl offset \(\Delta p_\mathrm{swirl}\) (
radial_equilibrium=True):Swirling flow exiting the domain carries a centrifugal pressure gradient. Enforcing a uniform pressure in opposition to this gradient would induce unnatural streamline curvature; instead the boundary pressure is adjusted to satisfy radial equilibrium. Pitch-averaged flow quantities are taken from the first interior layer (the offset-1 slice), the same source the outlet uses to extrapolate the boundary state:
\[\frac{dp_\mathrm{swirl}}{dr} = \frac{\overline{\rho V_\theta}\;\overline{V_\theta}}{r}\]where \(\overline{\Box}\) is the pitch mean. This product-of-means form matches the Multall
EXBCONDSradial-equilibrium treatment. Integrated from hub to tip, then broadcast uniformly in the pitch direction. The integration starts from zero at the hub, so the profile is zero at the hub, i.e. \(p_\mathrm{out}\) is enforced at the hub.- Parameters:
K_dyn (float, optional) – Scale factor for the dynamic head offset. Default 0 (off).
radial_equilibrium (bool, optional) – Include the radial equilibrium offset and use pitch-area-averaging for the dynamic head offset. Default True.
rf (float, optional) – Relaxation factor applied to the combined offset each step. Default 0.1.
- set_backflow(ho, s, Vr, Vt)[source]¶
Enable reversed-flow handling at the outlet.
Once enabled,
apply()detects cells with reversed axial flow and treats them as inlets: stagnation enthalpy, entropy, and transverse velocities are imposed from the values given here, and density is relaxed from the interior — exactly as inInletPatch. If reversed flow is detected without this method having been called,apply()raises aRuntimeError.All four arguments must be scalars.
- set_P(P)[source]¶
Set the prescribed outlet static pressure \(p_\mathrm{out}\).
Accepts a scalar or an array that broadcasts to
shape. Must be positive and finite. Non-scalar values are incompatible withset_throttle()andset_adjustment().- Parameters:
P (float or array) – Prescribed static pressure \(p_\mathrm{out}\) [Pa].
- set_throttle(mdot_target, K_pid)[source]¶
Set the mass flow target and PID gains for throttle control.
Each time step
update_target()computes a pressure correction \(\Delta p_\mathrm{throttle}\) and adds it to \(p_\mathrm{out}\):\[\Delta p_\mathrm{throttle} = K_p\, \varepsilon + K_i \int \varepsilon\, d\tau + K_d \frac{d\varepsilon}{d\tau}, \qquad \varepsilon = \dot{m} - \dot{m}_\mathrm{target}\]where \(\tau\) is pseudo-time, advanced each step by \(d\tau = \mathrm{cfl} \cdot L_\mathrm{ref} / V_\mathrm{ref}\).
Incompatible with non-scalar
P.
- get_throttle_stats()[source]¶
Return a dict of throttle state for convergence logging.
Keys¶
- mdot_targetfloat
Mass flow setpoint [kg/s]; zero when throttle is inactive.
- mdot_throttlefloat
Mass flow measured at the patch on the last call to
update_target()[kg/s].- P_throttlefloat
Total PID pressure correction \(\Delta p_\mathrm{throttle}\) [Pa].
- dP_Pfloat
Proportional contribution [Pa].
- dP_Ifloat
Integral contribution [Pa].
- dP_Dfloat
Derivative contribution [Pa].
- apply(rf=1.0)[source]¶
Impose outlet boundary conditions on the patch.
Forward-flow cells have static pressure imposed, with entropy and all three velocity components linearly extrapolated from the first two interior layers (
X_face = 2 * X_1 - X_2) and stored viaset_rho_u_Vxrt_nd(). If backflow handling has been enabled viaset_backflow(), reversed-flow cells are treated as inlets; seeInletPatch. If reversed flow is detected withoutset_backflow()having been called, aRuntimeErroris raised.- Parameters:
rf (float) – Relaxation factor for the reversed-cell density update.
- update_soln()[source]¶
Update \(\rho_\mathrm{soln}\) from the current interior density.
Should be called once per timestep before the Runge-Kutta stages so that density relaxation in reversed-flow cells during
apply()is anchored to the start-of-step density.
- update_target(cfl=None)[source]¶
Recompute the pressure target for the current timestep.
Runs the throttle PID (if active) and applies the spanwise adjustment (if configured). Should be called once per outer timestep before the Runge-Kutta stages.
- property K_pid¶
PID gains
(Kp, Ki, Kd)for throttle control; set viaset_throttle().
- property mdot_target¶
Mass flow target [kg/s] for throttle control; zero when throttle is inactive.
- class ember.mixing.MixingPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
RevolutionPatchCircumferentially averaged connection between blade rows.
Connects two block faces at a mixing plane by exchanging pitch-averaged flow state. Inflow nodes are treated as in
InletPatch; outflow nodes as inOutletPatch. Circumferential variations on each side are permitted; only the pitch average crosses the interface.Both sides must have the same spanwise resolution. Pitchwise resolution may differ.
- set_flux_avg()[source]¶
Compute pitch-averaged node fluxes and store in
flux_avg_nd.Called by
MixingCommunicatorbefore readingflux_avg_ndto form the cross-plane flux difference. Must be called with the block in interface coordinates so thatVxis the face-normal velocity andVris the spanwise velocity.
- set_target(target=None)[source]¶
Set the pitch-uniform inout target from the current block state or an explicit array.
MixingCommunicatorcalls this to write back the updated cross-plane target after each exchange. Iftargetis omitted, the pitch mean of the current block state is used to initialise the target before the first exchange.- Parameters:
target (array of shape
(nspan, 5), optional) – Nondimensional[ho, s, Vr, Vt, P]target values.
- get_target()[source]¶
Return the inout target as a nondimensional
(nspan, 5)array of[ho, s, Vr, Vt, P].Read by
MixingCommunicatorduring the exchange to form the average target across the mixing plane.
- apply()[source]¶
Impose mixing-plane boundary conditions on the patch.
Called each Runge-Kutta stage after
MixingCommunicatorhas updated the target viaset_target(). Inflow nodes are treated as inInletPatch: stagnation enthalpy, entropy, and transverse velocities are imposed from the target and static pressure is relaxed toward a linear extrapolation of the first two interior layers using the relaxation factorrf(used directly as the convex weight toward the first interior layer, no Mach scaling). Outflow nodes are treated as inOutletPatch: target static pressure is imposed and entropy plus all three velocity components are linearly extrapolated from the first two interior layers.
- attach_to_block(block)[source]¶
Attach to block and allocate internal storage.
Safe to call repeatedly; an existing
_targetof the correct shape is preserved so targets set before re-attachment are not lost._targetitself is left unallocated (None) until first used –set_target()andget_target()seed it lazily from the current block state – so a fresh attach never masks the “nothing has set a real target yet” state behind a zero-filled array.
- check_match(other, rtol=1e-05)[source]¶
Check if this MixingPatch matches another for pairing purposes.
MixingPatch matching requires x,r coordinates to match at all spanwise nodes (pitch-averaged), ignoring theta. Patches must have the same spanwise resolution but can have different pitchwise resolutions.
- Parameters:
- Returns:
None if patches do not match. False if they match with no spanwise flip needed. True if they match but other’s span must be reversed. Always test with
is not None; do not use as a bare truthiness check since False is a valid match result.- Return type:
bool or None
- update_soln()[source]¶
Update \(p_\mathrm{soln}\) from the current face static pressure.
Should be called once per timestep before the Runge-Kutta stages so that the inflow pressure relaxation in
apply()is anchored to the start-of-step pressure; seeInletPatch.
- property flux_avg_nd¶
Pitch-averaged flux array, shape
(nspan, 5); populated byset_flux_avg()and read byMixingCommunicatorto form the cross-plane flux difference.
- class ember.nonmatch.NonMatchPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
PatchNon-matching interface between block faces with different node counts.
Connects two block faces that occupy the same physical space but have different nodal distributions. Conserved variables are transferred via bilinear parametric interpolation by
NonMatchCommunicator, which precomputes parametric coordinates at initialisation and interpolates each step.Unlike
PeriodicPatch, which requires identical node distributions, andMixingPatch, which exchanges only the pitch average,NonMatchPatchtransfers the full pointwise solution across the interface.Corner x-r coordinates must match between paired faces. Pitchwise and spanwise node counts may differ freely.
- check_match(other, rtol=1e-06)[source]¶
Check if this NonMatchPatch matches another for pairing purposes.
NonMatchPatch matching requires only x,r coordinates to match at corners, allowing for different nodal distributions in the varying dimensions. Theta coordinates are ignored to allow for circumferential mismatch.
- class ember.rotating.RotatingPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
PatchRotating wall boundary with a prescribed angular velocity.
Overrides the wall angular velocity on the patch face used by the Fortran flux routines to compute wall-relative velocities. Faces without a
RotatingPatchdefault to the block angular velocityOmega.Angular velocity must be set via
set_Omega()orset_rpm()before the solver runs.- set_Omega(Omega)[source]¶
Set the wall angular velocity.
- Parameters:
Omega (float) – Angular velocity [rad/s]. Must be a scalar.
- set_rpm(rpm)[source]¶
Set the wall angular velocity from revolutions per minute.
Converts via \(\Omega = \mathrm{rpm} \cdot 2\pi / 60\).
- Parameters:
rpm (float) – Rotational speed [rev/min].
- property Omega¶
Angular velocity [rad/s].
- property rpm¶
Angular velocity in revolutions per minute [rpm].
- class ember.cooling.CoolingPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
PatchCooling flow through a boundary.
- class ember.inviscid.InviscidPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
PatchFrictionless slip-wall boundary.
Marks a face as impermeable but frictionless. The patch is included in the
slipcollection, which causes the Fortran flux routines to apply a slip (zero normal-velocity) condition without viscous stress. Use this instead of a no-slip wall when viscous effects on that face should be suppressed, for example on a symmetry plane or an inviscid endwall.
- class ember.cusp.CuspPatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
PatchCusp boundary at a modelled trailing edge.
Marks the faces either side of a zero-thickness trailing edge where two block faces meet at a cusp. Each solver step the conserved variables at the cusp nodes (the axial range covered by the patch) are averaged across the two faces so that the solution remains continuous at the trailing edge.
Must be on a constant-k face and must span the full j extent of the block. Paired with the corresponding face on the other side of the trailing edge via
check_match().
- class ember.probe.ProbePatch(i=(0, -1), j=(0, -1), k=(0, -1), label=None)[source]¶
Bases:
PatchPassive flow-sampling probe (Turbostream 3 kind 8).
Records flow history at a point, face, or interior plane. Unlike boundary patches it does not affect wall/slip treatment of the sampled face – it is deliberately excluded from
PERMEABLE_TYPES/SLIP_TYPES. The two class flags below relax the generic patch rules so a probe can be placed on an interior constant plane and may coincide with another patch.
Collections¶
- class ember.collections.BlockPatchCollection(block)[source]¶
Bases:
_LabelledListInitialise with a reference to the parent block.
- Parameters:
block (
Block) – The block whose boundary conditions this collection manages.
- extend(patches)[source]¶
Attach each patch to the block, validate limits and overlaps, then add all.
- insert(index, patch)[source]¶
Attach patch to the block, validate limits and overlaps, then insert at index.
- property cooling¶
All
CoolingPatchobjects.
- property inlet¶
All
InletPatchobjects.
- property inviscid¶
All
InviscidPatchobjects.
- property mixing¶
All
MixingPatchobjects.
- property outlet¶
All
OutletPatchobjects.
- property periodic¶
All
PeriodicPatchobjects.
- property permeable¶
Patches through which flow passes (non-wall faces).
Includes
InletPatch,OutletPatch,PeriodicPatch,MixingPatch,NonMatchPatch, andCuspPatch. Used to identify which boundary faces are not solid walls when computing block boundary fluxes.
- property probe¶
All
ProbePatchobjects.
- property rotating¶
All
RotatingPatchobjects.
- property slip¶
Patches that impose no friction (permeable faces and inviscid walls).
Union of
permeableandInviscidPatch. Used when applying viscous wall functions: faces in this set are treated as frictionless so no friction is applied at those boundaries.
- clear()¶
Remove all items from collection.
- index(item, start=0, stop=None)¶
Return index of first occurrence of item.
- property labels¶
List of item labels, in order, including
Nonefor unlabelled items.- Returns:
The
labelof each item in the collection. Entries areNonewhere an item has no label.- Return type:
- pop(index=-1)¶
Remove and return item at index (default last).
- Parameters:
index (int, optional) – Index of item to remove and return. Default is -1 (last item).
- Returns:
The removed item.
- Return type:
Any
- remove(item)¶
Remove first occurrence of item.
- Parameters:
item (Any) – Item to remove.
- class ember.collections.GridPatchCollection(grid)[source]¶
Bases:
objectInitialise with a reference to the parent grid.
- Parameters:
grid (
Grid) – The grid whose block patch collections this view aggregates.
- property cooling¶
Return all cooling patches from all blocks.
- property inlet¶
Return all inlet patches from all blocks.
- property mixing¶
Return all mixing patches from all blocks.
- property outlet¶
Return all outlet patches from all blocks.
- property periodic¶
Return all periodic patches from all blocks.
- property probe¶
Return all probe patches from all blocks.
- property rotating¶
Return all rotating patches from all blocks.