1use crate::geometry::{Face, FaceArray};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
47pub enum BoundaryKind {
48 Symmetric,
51 AntiSymmetric,
55 Custom,
59 Radiative,
61 #[default]
62 Free,
63 StrongDirichlet,
67 WeakDirichlet,
68}
69
70impl BoundaryKind {
71 pub fn needs_ghost(self) -> bool {
73 match self {
74 BoundaryKind::AntiSymmetric | BoundaryKind::Symmetric | BoundaryKind::Custom => true,
75 BoundaryKind::Radiative
76 | BoundaryKind::Free
77 | BoundaryKind::StrongDirichlet
78 | BoundaryKind::WeakDirichlet => false,
79 }
80 }
81
82 pub fn class(self) -> BoundaryClass {
83 match self {
84 BoundaryKind::AntiSymmetric | BoundaryKind::Symmetric | BoundaryKind::Custom => {
85 BoundaryClass::Ghost
86 }
87 BoundaryKind::Radiative
88 | BoundaryKind::StrongDirichlet
89 | BoundaryKind::WeakDirichlet
90 | BoundaryKind::Free => BoundaryClass::OneSided,
91 }
92 }
93}
94
95#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
96pub enum BoundaryClass {
97 #[default]
98 OneSided,
99 Ghost,
100 Periodic,
101}
102
103impl BoundaryClass {
104 pub fn has_ghost(self) -> bool {
105 matches!(self, BoundaryClass::Ghost | BoundaryClass::Periodic)
106 }
107}
108
109#[derive(Clone, Copy, Debug)]
111pub struct RadiativeParams {
112 pub target: f64,
114 pub speed: f64,
116}
117
118impl RadiativeParams {
119 pub fn lightlike(target: f64) -> Self {
122 Self { target, speed: 1.0 }
123 }
124}
125
126#[derive(Clone, Copy, Debug)]
127pub struct DirichletParams {
128 pub target: f64,
129 pub strength: f64,
130}
131
132pub trait BoundaryConds<const N: usize>: Clone {
135 fn kind(&self, _face: Face<N>) -> BoundaryKind;
136
137 fn radiative(&self, _position: [f64; N]) -> RadiativeParams {
138 RadiativeParams {
139 target: 0.0,
140 speed: 1.0,
141 }
142 }
143
144 fn dirichlet(&self, _position: [f64; N]) -> DirichletParams {
145 DirichletParams {
146 target: 0.0,
147 strength: 1.0,
148 }
149 }
150}
151
152pub fn is_boundary_compatible<const N: usize, B: BoundaryConds<N>>(
154 boundary: &FaceArray<N, BoundaryClass>,
155 conditions: &B,
156) -> bool {
157 Face::iterate()
158 .map(|face| conditions.kind(face).class() == boundary[face])
159 .all(|x| x)
160}
161
162pub trait SystemBoundaryConds<const N: usize>: Clone {
164 fn kind(&self, channel: usize, _face: Face<N>) -> BoundaryKind;
165
166 fn radiative(&self, _channel: usize, _position: [f64; N]) -> RadiativeParams {
167 RadiativeParams {
168 target: 0.0,
169 speed: 1.0,
170 }
171 }
172
173 fn dirichlet(&self, _channel: usize, _position: [f64; N]) -> DirichletParams {
174 DirichletParams {
175 target: 0.0,
176 strength: 1.0,
177 }
178 }
179
180 fn field(&self, channel: usize) -> FieldBoundaryConds<N, Self> {
181 FieldBoundaryConds::new(self.clone(), channel)
182 }
183}
184
185pub struct FieldBoundaryConds<const N: usize, C> {
188 conditions: C,
189 channel: usize,
190}
191
192impl<const N: usize, C: SystemBoundaryConds<N>> FieldBoundaryConds<N, C> {
193 pub const fn new(conditions: C, channel: usize) -> Self {
194 Self {
195 channel,
196 conditions,
197 }
198 }
199}
200
201impl<const N: usize, C: SystemBoundaryConds<N>> Clone for FieldBoundaryConds<N, C> {
202 fn clone(&self) -> Self {
203 Self {
204 conditions: self.conditions.clone(),
205 channel: self.channel,
206 }
207 }
208}
209
210impl<const N: usize, C: SystemBoundaryConds<N>> BoundaryConds<N> for FieldBoundaryConds<N, C> {
211 fn kind(&self, face: Face<N>) -> BoundaryKind {
212 self.conditions.kind(self.channel, face)
213 }
214
215 fn radiative(&self, position: [f64; N]) -> RadiativeParams {
216 self.conditions.radiative(self.channel, position)
217 }
218
219 fn dirichlet(&self, position: [f64; N]) -> DirichletParams {
220 self.conditions.dirichlet(self.channel, position)
221 }
222}
223
224#[derive(Clone)]
230pub struct ScalarConditions<I>(pub I);
231
232impl<I> ScalarConditions<I> {
233 pub const fn new(inner: I) -> Self {
234 Self(inner)
235 }
236}
237
238impl<const N: usize, I: BoundaryConds<N>> SystemBoundaryConds<N> for ScalarConditions<I> {
239 fn kind(&self, channel: usize, face: Face<N>) -> BoundaryKind {
240 debug_assert!(channel == 0);
241 self.0.kind(face)
242 }
243
244 fn radiative(&self, channel: usize, position: [f64; N]) -> RadiativeParams {
245 debug_assert!(channel == 0);
246 self.0.radiative(position)
247 }
248
249 fn dirichlet(&self, channel: usize, position: [f64; N]) -> DirichletParams {
250 debug_assert!(channel == 0);
251 self.0.dirichlet(position)
252 }
253}
254
255#[derive(Clone)]
256pub struct EmptyConditions;
257
258impl<const N: usize> SystemBoundaryConds<N> for EmptyConditions {
259 fn kind(&self, _channel: usize, _face: Face<N>) -> BoundaryKind {
260 unreachable!()
261 }
262
263 fn radiative(&self, _channel: usize, _position: [f64; N]) -> RadiativeParams {
264 unreachable!()
265 }
266
267 fn dirichlet(&self, _channel: usize, _position: [f64; N]) -> DirichletParams {
268 unreachable!()
269 }
270}