Skip to main content

VofSolidificationMelting

Struct VofSolidificationMelting 

Source
pub struct VofSolidificationMelting { /* private fields */ }
Expand description

Solidification and melting of the condensed phase of a VoF simulation.

§How this differs from the enthalpy-porosity model

SolidificationMelting derives its liquid fraction by integrating an under-relaxed enthalpy update, so latent heat feeds back on the temperature and holds a melting cell at its melting point. This model does not integrate anything: the solid fraction is read straight off a table alphaSolid(T), capped by however much of the cell the VoF phase occupies. It is the cruder of the two, and the right one only when the interface tracking — not the phase-change thermodynamics — is what the calculation is about.

It also carries no buoyancy term. The enthalpy-porosity model supplies its own Boussinesq force; here the host VoF solver already carries gravity through its p_rgh formulation, so adding one would double-count it.

§The two meanings of relax — an upstream trap

Both models take a relax coefficient defaulting to 0.9, and they mean different things:

  • Enthalpy-porosity: relax scales the increment, α₁ ← α₁ + relax·Cp·(T − T_liq_eff)/L. Raising it makes the update larger.
  • Here: relax is a convex blend between the new and old value, αₛ ← min(relax·α_vof·αₛ(T) + (1 − relax)·αₛ_old, α_vof). Raising it makes the update approach the table value faster, and relax = 1 discards the history entirely.

Transplanting a tuned relax from one model to the other is therefore not meaningful. This port keeps both upstream behaviours exactly as written rather than unifying them.

§State

Stateful, like the enthalpy-porosity model: it holds the solid fraction and its previous-timestep value, because the latent-heat source is a rate.

Implementations§

Source§

impl VofSolidificationMelting

Source

pub fn new( name: impl Into<String>, velocity_name: impl Into<String>, energy_name: impl Into<String>, selection: CellSelection, solid_fraction_table: TemperatureTable, latent_heat: f64, n_cells: usize, ) -> Self

Build the model with upstream’s numerical defaults.

  • name — identifier for diagnostics, upstream’s dictionary key.
  • velocity_name / energy_name — the equations this contributes to, upstream’s addSupFields returning {"U", thermo1().he().name()}.
  • selection — the cells acted on, upstream’s cellZone.
  • solid_fraction_table — upstream’s alphaSolidT, solid fraction [-] against temperature [K]. It descends: 1 when cold, 0 when hot. That is the opposite sense to the drag table SolidificationPorosity gives the same TemperatureTable type; the type is shared because the interpolation and end-clamping are identical, not because the quantity is, and it carries no unit of its own.
  • latent_heat — L [J/kg].

Defaults applied: relax = 0.9, Cu = 1e5, q = 1e-3, matching upstream’s documented defaults.

n_cells is the mesh cell count, needed to size the internal state.

Source

pub fn with_coefficients( self, relaxation: f64, darcy_coefficient: f64, darcy_regularisation: f64, ) -> Self

Override the numerical coefficients.

relaxation [-] in [0, 1] — the convex blend described on the type, not the enthalpy-porosity model’s increment scale. darcy_coefficient Cu and darcy_regularisation q have the same meaning as in SolidificationMeltingCoefficients: Cu sets the drag magnitude, q bounds it in a fully solid cell.

Source

pub fn name(&self) -> &str

The model’s name.

Source

pub fn velocity_name(&self) -> &str

The velocity field this adds a momentum sink to.

Source

pub fn energy_name(&self) -> &str

The energy field this adds latent heat to.

Source

pub fn selection(&self) -> &CellSelection

The cells acted on.

Source

pub fn solid_fraction(&self) -> &[f64]

The current solid fraction [-], indexed by position within the selection (not by mesh cell index).

Source

pub fn correct( &mut self, temperature: &VolScalarField, vof_phase_fraction: &VolScalarField, )

Advance the solid fraction from the current temperature and VoF phase fraction — upstream’s correct().

αₛ ← min(relax·α_vof·αₛ(T) + (1 − relax)·αₛ_old, α_vof)

The min against α_vof is what stops the model claiming more solid than there is condensed phase in the cell: with relax < 1 the blend can otherwise carry a stale value forward past a receding interface.

§No once-per-timestep guard

Unlike SolidificationMelting::update, this has none, because upstream’s correct() is called by the solver at a defined point in the timestep rather than lazily from addSup. Call it exactly once per timestep, before the equations that use it. Calling it twice applies the relaxation twice, exactly as it would upstream.

Source

pub fn advance_time(&mut self)

Roll the solid-fraction history forward.

Upstream’s alphaSolid_.oldTime() at the top of correct(). Call once per completed timestep; the latent-heat source is proportional to ∂(ρα_s)/∂t and is silently wrong without it.

Source

pub fn darcy_coefficient(&self, fluid_fraction: f64) -> f64

The Darcy drag coefficient at a given fluid fraction [1/s] per unit density.

Cu (1 − α_fluid)² / (α_fluid³ + q), where α_fluid = 1 − αₛ. Positive here, because upstream writes the sink as Sp -= Vc·ρ·S with a positive S; see add_momentum_source for why that ends up the same drag as the enthalpy-porosity model’s negative one.

Source

pub fn add_momentum_source( &self, rho: &VolScalarField, eqn: &mut FvVectorMatrix, )

Add the momentum sink to a velocity equation.

Upstream’s addSup(rho, U, eqn):

const scalar alphaFluid = 1 - alphaSolid_[celli];
const scalar S = Cu_*sqr(1 - alphaFluid)/(pow3(alphaFluid) + q_);
Sp[celli] -= Vc*rho[celli]*S;
§Why the sign looks opposite to the enthalpy-porosity model

It is not. Upstream writes the base fvModel as Sp += Vc·S with S = −Cu(1−α₁)²/(α₁³+q) and this one as Sp −= Vc·ρ·S with a positive S; the two products are the same negative number, modulo the density weighting. Both then pass through the solve(UEqn == fvModels.source(...)) negation described on SolidificationMelting::add_momentum_source, reaching the solved system as a positive diagonal contribution — a stabilising sink. This port therefore places it the same way: diag += V·ρ·Cu(1−α_fluid)²/(α_fluid³+q).

Source

pub fn add_enthalpy_source( &self, rho: &VolScalarField, dt: f64, eqn: &mut FvMatrix, )

Add the latent-heat source to an enthalpy equation.

Upstream’s addSup(alpha, rho, he, eqn), which is the single line eqn += L*(fvc::ddt(rho, alphaSolid_)). Following it through the solve(hEqn == fvModels.source(...)) negation, the term reaching the solved right-hand side is −L·∂(ρα_s)/∂t: freezing (∂α_s/∂t > 0) releases energy, so it appears as a negative contribution to an equation whose sources are subtracted.

§Enthalpy only — an upstream limitation kept, not corrected

SolidificationMelting::add_energy_source branches on whether the equation is solved in temperature or enthalpy and divides by Cp in the temperature form. This model has no such branch upstream — it is only ever attached to thermo1().he(), an enthalpy — so none is added here. Attaching it to a temperature equation would over-source it by a factor of Cp, typically several hundred. That restriction is upstream’s and is reproduced rather than papered over.

dt is the timestep [s]; a non-positive dt contributes nothing.

Trait Implementations§

Source§

impl Clone for VofSolidificationMelting

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for VofSolidificationMelting

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for VofSolidificationMelting

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for VofSolidificationMelting

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.