use super::{CellSelection, TemperatureTable};
use crate::fields::VolScalarField;
use crate::ldu_matrix::FvVectorMatrix;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MomentumEquationForm {
Kinematic,
DensityWeighted,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SolidificationPorosity {
name: String,
velocity_name: String,
selection: CellSelection,
drag: TemperatureTable,
form: MomentumEquationForm,
phase_fraction_name: Option<String>,
}
impl SolidificationPorosity {
#[must_use]
pub fn new(
name: impl Into<String>,
velocity_name: impl Into<String>,
selection: CellSelection,
drag: TemperatureTable,
form: MomentumEquationForm,
) -> Self {
Self {
name: name.into(),
velocity_name: velocity_name.into(),
selection,
drag,
form,
phase_fraction_name: None,
}
}
#[must_use]
pub fn with_phase_fraction(mut self, alpha_name: impl Into<String>) -> Self {
self.phase_fraction_name = Some(alpha_name.into());
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 phase_fraction_name(&self) -> Option<&str> {
self.phase_fraction_name.as_deref()
}
#[must_use]
pub fn selection(&self) -> &CellSelection {
&self.selection
}
#[must_use]
pub fn drag_table(&self) -> &TemperatureTable {
&self.drag
}
#[must_use]
pub fn form(&self) -> MomentumEquationForm {
self.form
}
pub fn add_momentum_source(
&self,
temperature: &VolScalarField,
rho: &VolScalarField,
phase_fraction: Option<&VolScalarField>,
eqn: &mut FvVectorMatrix,
) {
let mesh = eqn.mesh.clone();
let cells = self.selection.cells(mesh.n_cells);
for &cell in &cells {
let v = mesh.cell_volumes[cell];
let alpha = phase_fraction.map_or(1.0, |a| a.internal[cell]);
let density = match self.form {
MomentumEquationForm::Kinematic => 1.0,
MomentumEquationForm::DensityWeighted => rho.internal[cell],
};
let d = self.drag.value(temperature.internal[cell]);
eqn.ldu.diag[cell] += v * alpha * density * d;
}
}
#[must_use]
pub fn force_diagonal(
&self,
temperature: &VolScalarField,
rho: &VolScalarField,
phase_fraction: Option<&VolScalarField>,
cell_volumes: &[f64],
) -> Vec<f64> {
let n_cells = temperature.internal.len();
self.selection
.cells(n_cells)
.iter()
.map(|&cell| {
let alpha = phase_fraction.map_or(1.0, |a| a.internal[cell]);
let density = match self.form {
MomentumEquationForm::Kinematic => 1.0,
MomentumEquationForm::DensityWeighted => rho.internal[cell],
};
cell_volumes[cell] * alpha * density * self.drag.value(temperature.internal[cell])
})
.collect()
}
}
#[cfg(test)]
mod tests;