1use crate::data::atlas::Atlas;
8use crate::data::section::Section;
9use crate::data::storage::Storage;
10use crate::mesh_error::MeshSieveError;
11use crate::topology::point::PointId;
12
13#[derive(Clone, Debug)]
15pub struct HighOrderCoordinates<V, S: Storage<V>> {
16 dimension: usize,
17 section: Section<V, S>,
18}
19
20impl<V, S> HighOrderCoordinates<V, S>
21where
22 S: Storage<V>,
23{
24 #[inline]
26 pub fn dimension(&self) -> usize {
27 self.dimension
28 }
29
30 #[inline]
32 pub fn section(&self) -> &Section<V, S> {
33 &self.section
34 }
35
36 #[inline]
38 pub fn section_mut(&mut self) -> &mut Section<V, S> {
39 &mut self.section
40 }
41}
42
43impl<V, S> HighOrderCoordinates<V, S>
44where
45 V: Clone + Default,
46 S: Storage<V> + Clone,
47{
48 pub fn try_new(dimension: usize, atlas: Atlas) -> Result<Self, MeshSieveError> {
52 validate_high_order_dimension(dimension, &atlas)?;
53 Ok(Self {
54 dimension,
55 section: Section::new(atlas),
56 })
57 }
58
59 pub fn from_section(dimension: usize, section: Section<V, S>) -> Result<Self, MeshSieveError> {
61 validate_high_order_dimension(dimension, section.atlas())?;
62 Ok(Self { dimension, section })
63 }
64}
65
66#[derive(Clone, Debug)]
68pub struct MeshVelocity<V, S: Storage<V>> {
69 dimension: usize,
70 section: Section<V, S>,
71}
72
73impl<V, S> MeshVelocity<V, S>
74where
75 S: Storage<V>,
76{
77 #[inline]
79 pub fn dimension(&self) -> usize {
80 self.dimension
81 }
82
83 #[inline]
85 pub fn section(&self) -> &Section<V, S> {
86 &self.section
87 }
88
89 #[inline]
91 pub fn section_mut(&mut self) -> &mut Section<V, S> {
92 &mut self.section
93 }
94
95 #[inline]
97 pub fn try_restrict(&self, p: PointId) -> Result<&[V], MeshSieveError> {
98 self.section.try_restrict(p)
99 }
100
101 #[inline]
103 pub fn try_restrict_mut(&mut self, p: PointId) -> Result<&mut [V], MeshSieveError> {
104 self.section.try_restrict_mut(p)
105 }
106}
107
108impl<V, S> MeshVelocity<V, S>
109where
110 V: Clone + Default,
111 S: Storage<V> + Clone,
112{
113 pub fn try_new(dimension: usize, atlas: Atlas) -> Result<Self, MeshSieveError> {
117 validate_dimension(dimension, &atlas)?;
118 Ok(Self {
119 dimension,
120 section: Section::new(atlas),
121 })
122 }
123
124 pub fn from_section(dimension: usize, section: Section<V, S>) -> Result<Self, MeshSieveError> {
126 validate_dimension(dimension, section.atlas())?;
127 Ok(Self { dimension, section })
128 }
129
130 pub fn try_add_point(&mut self, p: PointId) -> Result<(), MeshSieveError> {
132 self.section.try_add_point(p, self.dimension)
133 }
134}
135
136#[derive(Clone, Debug)]
138pub struct Coordinates<V, S: Storage<V>> {
139 topological_dimension: usize,
140 embedding_dimension: usize,
141 section: Section<V, S>,
142 high_order: Option<HighOrderCoordinates<V, S>>,
143}
144
145impl<V, S> Coordinates<V, S>
146where
147 S: Storage<V>,
148{
149 #[inline]
151 pub fn dimension(&self) -> usize {
152 self.embedding_dimension
153 }
154
155 #[inline]
157 pub fn topological_dimension(&self) -> usize {
158 self.topological_dimension
159 }
160
161 #[inline]
163 pub fn embedding_dimension(&self) -> usize {
164 self.embedding_dimension
165 }
166
167 #[inline]
169 pub fn section(&self) -> &Section<V, S> {
170 &self.section
171 }
172
173 #[inline]
175 pub fn section_mut(&mut self) -> &mut Section<V, S> {
176 &mut self.section
177 }
178
179 #[inline]
181 pub fn high_order(&self) -> Option<&HighOrderCoordinates<V, S>> {
182 self.high_order.as_ref()
183 }
184
185 #[inline]
187 pub fn high_order_mut(&mut self) -> Option<&mut HighOrderCoordinates<V, S>> {
188 self.high_order.as_mut()
189 }
190
191 pub fn set_high_order(
193 &mut self,
194 high_order: HighOrderCoordinates<V, S>,
195 ) -> Result<(), MeshSieveError> {
196 if high_order.dimension != self.embedding_dimension {
197 return Err(MeshSieveError::InvalidGeometry(format!(
198 "higher-order coordinate dimension {} does not match base dimension {}",
199 high_order.dimension, self.embedding_dimension
200 )));
201 }
202 self.high_order = Some(high_order);
203 Ok(())
204 }
205
206 #[inline]
208 pub fn into_section(self) -> Section<V, S> {
209 self.section
210 }
211
212 #[inline]
214 pub fn try_restrict(&self, p: PointId) -> Result<&[V], MeshSieveError> {
215 self.section.try_restrict(p)
216 }
217
218 #[inline]
220 pub fn try_restrict_mut(&mut self, p: PointId) -> Result<&mut [V], MeshSieveError> {
221 self.section.try_restrict_mut(p)
222 }
223}
224
225impl<S> Coordinates<f64, S>
226where
227 S: Storage<f64>,
228{
229 pub fn advance_with_velocity<St>(
231 &mut self,
232 velocity: &MeshVelocity<f64, St>,
233 dt: f64,
234 ) -> Result<(), MeshSieveError>
235 where
236 St: Storage<f64>,
237 {
238 let dim = self.embedding_dimension;
239 let points: Vec<PointId> = self.section.atlas().points().collect();
240 for point in points {
241 let vel = velocity.try_restrict(point)?;
242 if vel.len() != dim {
243 return Err(MeshSieveError::SliceLengthMismatch {
244 point,
245 expected: dim,
246 found: vel.len(),
247 });
248 }
249 let coord = self.try_restrict_mut(point)?;
250 if coord.len() != dim {
251 return Err(MeshSieveError::SliceLengthMismatch {
252 point,
253 expected: dim,
254 found: coord.len(),
255 });
256 }
257 for (coord_value, vel_value) in coord.iter_mut().zip(vel.iter()) {
258 *coord_value += dt * vel_value;
259 }
260 }
261 Ok(())
262 }
263}
264
265impl<V, S> Coordinates<V, S>
266where
267 V: Clone + Default,
268 S: Storage<V> + Clone,
269{
270 pub fn try_new(
275 topological_dimension: usize,
276 embedding_dimension: usize,
277 atlas: Atlas,
278 ) -> Result<Self, MeshSieveError> {
279 validate_coordinate_dimensions(topological_dimension, embedding_dimension, &atlas)?;
280 Ok(Self {
281 topological_dimension,
282 embedding_dimension,
283 section: Section::new(atlas),
284 high_order: None,
285 })
286 }
287
288 pub fn from_section(
290 topological_dimension: usize,
291 embedding_dimension: usize,
292 section: Section<V, S>,
293 ) -> Result<Self, MeshSieveError> {
294 validate_coordinate_dimensions(
295 topological_dimension,
296 embedding_dimension,
297 section.atlas(),
298 )?;
299 Ok(Self {
300 topological_dimension,
301 embedding_dimension,
302 section,
303 high_order: None,
304 })
305 }
306
307 pub fn try_add_point(&mut self, p: PointId) -> Result<(), MeshSieveError> {
309 self.section.try_add_point(p, self.embedding_dimension)
310 }
311}
312
313fn validate_coordinate_dimensions(
314 topological_dimension: usize,
315 embedding_dimension: usize,
316 atlas: &Atlas,
317) -> Result<(), MeshSieveError> {
318 if embedding_dimension == 0 {
319 return Err(MeshSieveError::ZeroLengthSlice);
320 }
321 if topological_dimension > embedding_dimension {
322 return Err(MeshSieveError::InvalidGeometry(format!(
323 "topological dimension {topological_dimension} exceeds embedding dimension {embedding_dimension}"
324 )));
325 }
326 for (point, (_offset, len)) in atlas.iter_entries() {
327 if len != embedding_dimension {
328 return Err(MeshSieveError::SliceLengthMismatch {
329 point,
330 expected: embedding_dimension,
331 found: len,
332 });
333 }
334 }
335 Ok(())
336}
337
338fn validate_dimension(dimension: usize, atlas: &Atlas) -> Result<(), MeshSieveError> {
339 if dimension == 0 {
340 return Err(MeshSieveError::ZeroLengthSlice);
341 }
342 for (point, (_offset, len)) in atlas.iter_entries() {
343 if len != dimension {
344 return Err(MeshSieveError::SliceLengthMismatch {
345 point,
346 expected: dimension,
347 found: len,
348 });
349 }
350 }
351 Ok(())
352}
353
354fn validate_high_order_dimension(dimension: usize, atlas: &Atlas) -> Result<(), MeshSieveError> {
355 if dimension == 0 {
356 return Err(MeshSieveError::ZeroLengthSlice);
357 }
358 for (point, (_offset, len)) in atlas.iter_entries() {
359 if len == 0 || len % dimension != 0 {
360 return Err(MeshSieveError::SliceLengthMismatch {
361 point,
362 expected: dimension,
363 found: len,
364 });
365 }
366 }
367 Ok(())
368}
369
370#[cfg(test)]
371mod tests {
372 use super::{Coordinates, MeshVelocity};
373 use crate::data::atlas::Atlas;
374 use crate::data::storage::VecStorage;
375 use crate::topology::point::PointId;
376
377 #[test]
378 fn advance_coordinates_over_multiple_steps() {
379 let mut atlas = Atlas::default();
380 let p1 = PointId::new(1).unwrap();
381 let p2 = PointId::new(2).unwrap();
382 atlas.try_insert(p1, 3).unwrap();
383 atlas.try_insert(p2, 3).unwrap();
384
385 let mut coords = Coordinates::<f64, VecStorage<f64>>::try_new(3, 3, atlas.clone()).unwrap();
386 let mut velocity = MeshVelocity::<f64, VecStorage<f64>>::try_new(3, atlas).unwrap();
387
388 coords.section_mut().try_set(p1, &[0.0, 0.0, 0.0]).unwrap();
389 coords.section_mut().try_set(p2, &[1.0, 1.0, 1.0]).unwrap();
390 velocity
391 .section_mut()
392 .try_set(p1, &[1.0, 0.0, -1.0])
393 .unwrap();
394 velocity
395 .section_mut()
396 .try_set(p2, &[0.5, -0.5, 1.0])
397 .unwrap();
398
399 let dt = 0.25;
400 for _ in 0..4 {
401 coords.advance_with_velocity(&velocity, dt).unwrap();
402 }
403
404 assert_eq!(coords.try_restrict(p1).unwrap(), &[1.0, 0.0, -1.0]);
405 assert_eq!(coords.try_restrict(p2).unwrap(), &[1.5, 0.5, 2.0]);
406 }
407}