use super::{CellSelection, TemperatureTable};
use crate::fields::VolScalarField;
use crate::ldu_matrix::{FvMatrix, FvVectorMatrix};
#[derive(Debug, Clone, PartialEq)]
pub struct VofSolidificationMelting {
name: String,
velocity_name: String,
energy_name: String,
selection: CellSelection,
solid_fraction_table: TemperatureTable,
latent_heat: f64,
relaxation: f64,
darcy_coefficient: f64,
darcy_regularisation: f64,
solid_fraction: Vec<f64>,
solid_fraction_old: Vec<f64>,
}
impl VofSolidificationMelting {
#[must_use]
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 {
let n = selection.len(n_cells);
Self {
name: name.into(),
velocity_name: velocity_name.into(),
energy_name: energy_name.into(),
selection,
solid_fraction_table,
latent_heat,
relaxation: 0.9,
darcy_coefficient: 1.0e5,
darcy_regularisation: 1.0e-3,
solid_fraction: vec![0.0; n],
solid_fraction_old: vec![0.0; n],
}
}
#[must_use]
pub fn with_coefficients(
mut self,
relaxation: f64,
darcy_coefficient: f64,
darcy_regularisation: f64,
) -> Self {
self.relaxation = relaxation;
self.darcy_coefficient = darcy_coefficient;
self.darcy_regularisation = darcy_regularisation;
self
}
#[must_use]
pub fn name(&self) -> &str {
&self.name
}
#[must_use]
pub fn velocity_name(&self) -> &str {
&self.velocity_name
}
#[must_use]
pub fn energy_name(&self) -> &str {
&self.energy_name
}
#[must_use]
pub fn selection(&self) -> &CellSelection {
&self.selection
}
#[must_use]
pub fn solid_fraction(&self) -> &[f64] {
&self.solid_fraction
}
pub fn correct(&mut self, temperature: &VolScalarField, vof_phase_fraction: &VolScalarField) {
let cells = self.selection.cells(temperature.internal.len());
for (i, &cell) in cells.iter().enumerate() {
let alpha_vof = vof_phase_fraction.internal[cell];
let table = self.solid_fraction_table.value(temperature.internal[cell]);
let blended = self.relaxation * alpha_vof * table
+ (1.0 - self.relaxation) * self.solid_fraction[i];
self.solid_fraction[i] = blended.min(alpha_vof);
}
}
pub fn advance_time(&mut self) {
self.solid_fraction_old
.copy_from_slice(&self.solid_fraction);
}
#[must_use]
pub fn darcy_coefficient(&self, fluid_fraction: f64) -> f64 {
let solid = 1.0 - fluid_fraction;
self.darcy_coefficient * solid * solid
/ (fluid_fraction * fluid_fraction * fluid_fraction + self.darcy_regularisation)
}
pub fn add_momentum_source(&self, rho: &VolScalarField, eqn: &mut FvVectorMatrix) {
let mesh = eqn.mesh.clone();
let cells = self.selection.cells(mesh.n_cells);
for (i, &cell) in cells.iter().enumerate() {
let v = mesh.cell_volumes[cell];
let fluid = 1.0 - self.solid_fraction[i];
eqn.ldu.diag[cell] += v * rho.internal[cell] * self.darcy_coefficient(fluid);
}
}
pub fn add_enthalpy_source(&self, rho: &VolScalarField, dt: f64, eqn: &mut FvMatrix) {
if dt <= 0.0 {
return;
}
let mesh = eqn.mesh.clone();
let cells = self.selection.cells(mesh.n_cells);
for (i, &cell) in cells.iter().enumerate() {
let v = mesh.cell_volumes[cell];
let rate =
rho.internal[cell] * (self.solid_fraction[i] - self.solid_fraction_old[i]) / dt;
eqn.source[cell] -= v * self.latent_heat * rate;
}
}
}
#[cfg(test)]
mod tests;