Skip to main content

conspire/domain/boundary/
mod.rs

1//! Boundary conditions on the degrees of freedom of a model.
2
3mod condition;
4
5pub use condition::{BoundaryCondition, BoundaryConditions, Enforcement};
6
7use crate::{
8    math::{
9        Current, Quantity, Tensor, TensorRank1, TensorTuple, TensorVector, optimize::Prescription,
10    },
11    units::{
12        Concentration as ConcentrationUnit, ElectricPotential, Length,
13        Temperature as TemperatureUnit, Velocity as VelocityUnit,
14    },
15};
16use std::marker::PhantomData;
17
18/// How the degrees of freedom are laid out, `STRIDE` to a node, indexed as `STRIDE * node + offset`.
19pub trait Layout {
20    const STRIDE: usize;
21}
22
23/// The state of a node, whose degrees of freedom are laid out in a way that is a function of it.
24pub trait NodalDof {
25    type Layout: Layout;
26}
27
28/// The state of the nodes, whose degrees of freedom are laid out in a way that is a function of it.
29pub trait NodalState {
30    type Layout: Layout;
31}
32
33/// The coordinates of a solid in `D` dimensions.
34pub struct Solid<const D: usize>;
35
36/// The velocities of a solid in `D` dimensions, such as the unknown of a dynamic solve.
37pub struct SolidRate<const D: usize>;
38
39/// A scalar field, named by its unit.
40pub struct Field<U>(PhantomData<U>);
41
42/// The degrees of freedom of a node in a layout, then those of a node in another layout.
43pub struct Coupled<A, B>(PhantomData<(A, B)>);
44
45/// The coordinates of a solid in `D` dimensions, then its temperature, to a node.
46pub type SolidThermal<const D: usize> = Coupled<Solid<D>, Field<TemperatureUnit>>;
47
48impl<const D: usize> Layout for Solid<D> {
49    const STRIDE: usize = D;
50}
51
52impl<const D: usize> Layout for SolidRate<D> {
53    const STRIDE: usize = D;
54}
55
56impl<U> Layout for Field<U> {
57    const STRIDE: usize = 1;
58}
59
60impl<A, B> Layout for Coupled<A, B>
61where
62    A: Layout,
63    B: Layout,
64{
65    const STRIDE: usize = A::STRIDE + B::STRIDE;
66}
67
68impl<const D: usize> NodalDof for TensorRank1<D, Current, Length> {
69    type Layout = Solid<D>;
70}
71
72impl<const D: usize> NodalDof for TensorRank1<D, Current, VelocityUnit> {
73    type Layout = SolidRate<D>;
74}
75
76impl<U> NodalDof for Quantity<U> {
77    type Layout = Field<U>;
78}
79
80impl<A, B> NodalDof for TensorTuple<A, B>
81where
82    A: NodalDof + Tensor,
83    B: NodalDof + Tensor,
84{
85    type Layout = Coupled<A::Layout, B::Layout>;
86}
87
88impl<N> NodalState for TensorVector<N>
89where
90    N: NodalDof,
91{
92    type Layout = N::Layout;
93}
94
95/// A component that a layout has directly.
96pub struct Direct;
97
98/// A component that the first layout of a coupled pair has, found by the index in it.
99pub struct Left<I>(PhantomData<I>);
100
101/// A component that the second layout of a coupled pair has, found by the index in it.
102pub struct Right<I>(PhantomData<I>);
103
104/// A degree of freedom of each node in a layout, at `OFFSET` within its node.
105///
106/// The index `I` is found by the compiler, from where the component is in a coupled layout.
107pub trait Component<L, I>
108where
109    L: Layout,
110{
111    const OFFSET: usize;
112}
113
114impl<A, B, C, I> Component<Coupled<A, B>, Left<I>> for C
115where
116    A: Layout,
117    B: Layout,
118    C: Component<A, I>,
119{
120    const OFFSET: usize = C::OFFSET;
121}
122
123impl<A, B, C, I> Component<Coupled<A, B>, Right<I>> for C
124where
125    A: Layout,
126    B: Layout,
127    C: Component<B, I>,
128{
129    const OFFSET: usize = A::STRIDE + C::OFFSET;
130}
131
132/// A component that can be held at a value.
133///
134/// A displacement is held at a distance from its initial value, and a field at its value.
135pub trait Prescribable {
136    type Value;
137    fn prescription(value: Self::Value) -> Prescription;
138}
139
140/// The displacement along an axis.
141#[derive(Clone, Copy)]
142pub struct Displacement<const AXIS: usize>;
143
144/// The velocity along an axis.
145#[derive(Clone, Copy)]
146pub struct Velocity<const AXIS: usize>;
147
148/// The temperature.
149#[derive(Clone, Copy)]
150pub struct Temperature;
151
152/// The electric potential.
153#[derive(Clone, Copy)]
154pub struct Potential;
155
156/// The molar concentration.
157#[derive(Clone, Copy)]
158pub struct Concentration;
159
160impl<const D: usize, const AXIS: usize> Component<Solid<D>, Direct> for Displacement<AXIS> {
161    const OFFSET: usize = {
162        assert!(AXIS < D, "The axis is not one of the dimensions.");
163        AXIS
164    };
165}
166
167impl<const D: usize, const AXIS: usize> Component<SolidRate<D>, Direct> for Velocity<AXIS> {
168    const OFFSET: usize = {
169        assert!(AXIS < D, "The axis is not one of the dimensions.");
170        AXIS
171    };
172}
173
174impl Component<Field<TemperatureUnit>, Direct> for Temperature {
175    const OFFSET: usize = 0;
176}
177
178impl Component<Field<ElectricPotential>, Direct> for Potential {
179    const OFFSET: usize = 0;
180}
181
182impl Component<Field<ConcentrationUnit>, Direct> for Concentration {
183    const OFFSET: usize = 0;
184}
185
186impl<const AXIS: usize> Prescribable for Displacement<AXIS> {
187    type Value = Quantity<Length>;
188    fn prescription(value: Self::Value) -> Prescription {
189        Prescription::Offset(value.value())
190    }
191}
192
193impl<const AXIS: usize> Prescribable for Velocity<AXIS> {
194    type Value = Quantity<VelocityUnit>;
195    fn prescription(value: Self::Value) -> Prescription {
196        Prescription::Absolute(value.value())
197    }
198}
199
200impl Prescribable for Temperature {
201    type Value = Quantity<TemperatureUnit>;
202    fn prescription(value: Self::Value) -> Prescription {
203        Prescription::Absolute(value.value())
204    }
205}
206
207impl Prescribable for Potential {
208    type Value = Quantity<ElectricPotential>;
209    fn prescription(value: Self::Value) -> Prescription {
210        Prescription::Absolute(value.value())
211    }
212}
213
214impl Prescribable for Concentration {
215    type Value = Quantity<ConcentrationUnit>;
216    fn prescription(value: Self::Value) -> Prescription {
217        Prescription::Absolute(value.value())
218    }
219}