use crate::geometry::{Face, FaceArray};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
pub enum BoundaryKind {
Symmetric,
AntiSymmetric,
Custom,
Radiative,
#[default]
Free,
StrongDirichlet,
WeakDirichlet,
}
impl BoundaryKind {
pub fn needs_ghost(self) -> bool {
match self {
BoundaryKind::AntiSymmetric | BoundaryKind::Symmetric | BoundaryKind::Custom => true,
BoundaryKind::Radiative
| BoundaryKind::Free
| BoundaryKind::StrongDirichlet
| BoundaryKind::WeakDirichlet => false,
}
}
pub fn class(self) -> BoundaryClass {
match self {
BoundaryKind::AntiSymmetric | BoundaryKind::Symmetric | BoundaryKind::Custom => {
BoundaryClass::Ghost
}
BoundaryKind::Radiative
| BoundaryKind::StrongDirichlet
| BoundaryKind::WeakDirichlet
| BoundaryKind::Free => BoundaryClass::OneSided,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
pub enum BoundaryClass {
#[default]
OneSided,
Ghost,
Periodic,
}
impl BoundaryClass {
pub fn has_ghost(self) -> bool {
matches!(self, BoundaryClass::Ghost | BoundaryClass::Periodic)
}
}
#[derive(Clone, Copy, Debug)]
pub struct RadiativeParams {
pub target: f64,
pub speed: f64,
}
impl RadiativeParams {
pub fn lightlike(target: f64) -> Self {
Self { target, speed: 1.0 }
}
}
#[derive(Clone, Copy, Debug)]
pub struct DirichletParams {
pub target: f64,
pub strength: f64,
}
pub trait BoundaryConds<const N: usize>: Clone {
fn kind(&self, _face: Face<N>) -> BoundaryKind;
fn radiative(&self, _position: [f64; N]) -> RadiativeParams {
RadiativeParams {
target: 0.0,
speed: 1.0,
}
}
fn dirichlet(&self, _position: [f64; N]) -> DirichletParams {
DirichletParams {
target: 0.0,
strength: 1.0,
}
}
}
pub fn is_boundary_compatible<const N: usize, B: BoundaryConds<N>>(
boundary: &FaceArray<N, BoundaryClass>,
conditions: &B,
) -> bool {
Face::iterate()
.map(|face| conditions.kind(face).class() == boundary[face])
.all(|x| x)
}
pub trait SystemBoundaryConds<const N: usize>: Clone {
fn kind(&self, channel: usize, _face: Face<N>) -> BoundaryKind;
fn radiative(&self, _channel: usize, _position: [f64; N]) -> RadiativeParams {
RadiativeParams {
target: 0.0,
speed: 1.0,
}
}
fn dirichlet(&self, _channel: usize, _position: [f64; N]) -> DirichletParams {
DirichletParams {
target: 0.0,
strength: 1.0,
}
}
fn field(&self, channel: usize) -> FieldBoundaryConds<N, Self> {
FieldBoundaryConds::new(self.clone(), channel)
}
}
pub struct FieldBoundaryConds<const N: usize, C> {
conditions: C,
channel: usize,
}
impl<const N: usize, C: SystemBoundaryConds<N>> FieldBoundaryConds<N, C> {
pub const fn new(conditions: C, channel: usize) -> Self {
Self {
channel,
conditions,
}
}
}
impl<const N: usize, C: SystemBoundaryConds<N>> Clone for FieldBoundaryConds<N, C> {
fn clone(&self) -> Self {
Self {
conditions: self.conditions.clone(),
channel: self.channel,
}
}
}
impl<const N: usize, C: SystemBoundaryConds<N>> BoundaryConds<N> for FieldBoundaryConds<N, C> {
fn kind(&self, face: Face<N>) -> BoundaryKind {
self.conditions.kind(self.channel, face)
}
fn radiative(&self, position: [f64; N]) -> RadiativeParams {
self.conditions.radiative(self.channel, position)
}
fn dirichlet(&self, position: [f64; N]) -> DirichletParams {
self.conditions.dirichlet(self.channel, position)
}
}
#[derive(Clone)]
pub struct ScalarConditions<I>(pub I);
impl<I> ScalarConditions<I> {
pub const fn new(inner: I) -> Self {
Self(inner)
}
}
impl<const N: usize, I: BoundaryConds<N>> SystemBoundaryConds<N> for ScalarConditions<I> {
fn kind(&self, channel: usize, face: Face<N>) -> BoundaryKind {
debug_assert!(channel == 0);
self.0.kind(face)
}
fn radiative(&self, channel: usize, position: [f64; N]) -> RadiativeParams {
debug_assert!(channel == 0);
self.0.radiative(position)
}
fn dirichlet(&self, channel: usize, position: [f64; N]) -> DirichletParams {
debug_assert!(channel == 0);
self.0.dirichlet(position)
}
}
#[derive(Clone)]
pub struct EmptyConditions;
impl<const N: usize> SystemBoundaryConds<N> for EmptyConditions {
fn kind(&self, _channel: usize, _face: Face<N>) -> BoundaryKind {
unreachable!()
}
fn radiative(&self, _channel: usize, _position: [f64; N]) -> RadiativeParams {
unreachable!()
}
fn dirichlet(&self, _channel: usize, _position: [f64; N]) -> DirichletParams {
unreachable!()
}
}