gmt_dos_clients_fem/lib.rs
1//! This module is used to build the state space model of the telescope structure
2//!
3//! A state space model is represented by the structure [DiscreteModalSolver] that is created using the builder [`DiscreteStateSpace`].
4//! The transformation of the FEM continuous 2nd order differential equation
5//! into a discrete state space model is performed by the [Exponential] structure
6//! (for the details of the transformation see the `exponential` module ).
7//!
8//! # Example
9//! The following example loads a FEM model and converts it into a state space model
10//! setting the sampling rate and the damping coefficients and truncating the eigen frequencies.
11//! A single input and a single output are selected.
12//! ```no_run
13//! use gmt_fem::FEM;
14//! use gmt_dos_clients_fem::{DiscreteStateSpace, DiscreteModalSolver,
15//! fem_io::{actors_inputs::OSSM1Lcl6F, actors_outputs::OSSM1Lcl}};
16//! #[cfg(not(feature = "cuda"))]
17//! use gmt_dos_clients_fem::solvers::Exponential;
18//! #[cfg(feature = "cuda")]
19//! use gmt_dos_clients_fem::solvers::{CuStateSpace, Exponential};
20//!
21//! # fn main() -> anyhow::Result<()> {
22//! let sampling_rate = 1e3; // Hz
23//! let fem = FEM::from_env()?;
24//! #[cfg(not(feature = "cuda"))]
25//! let mut fem_ss: DiscreteModalSolver<Exponential> = DiscreteStateSpace::from(fem)
26//! .sampling(sampling_rate)
27//! .proportional_damping(2. / 100.)
28//! .ins::<OSSM1Lcl6F>()
29//! .outs::<OSSM1Lcl>()
30//! .build()?;
31//! #[cfg(feature = "cuda")]
32//! let mut fem_ss: DiscreteModalSolver<CuStateSpace> = DiscreteStateSpace::<Exponential>::from(fem)
33//! .sampling(sampling_rate)
34//! .proportional_damping(2. / 100.)
35//! .ins::<OSSM1Lcl6F>()
36//! .outs::<OSSM1Lcl>()
37//! .build()?;
38//! # Ok::<(), anyhow::Error>(())
39//! # }
40//! ```
41
42use interface::{UniqueIdentifier, doublet::UidTuple};
43use std::{any::type_name, ops::Range};
44
45mod discrete_state_space;
46pub mod solvers;
47pub use discrete_state_space::{DiscreteStateSpace, StateSpaceError};
48mod discrete_modal_solver;
49pub use discrete_modal_solver::DiscreteModalSolver;
50pub mod actors_interface;
51#[cfg(feature = "serde")]
52mod impl_serde;
53mod model;
54pub use model::{Model, Switch, fem_io};
55
56use solvers::Solver;
57
58/* #[cfg(feature = "serde")]
59pub trait Solver: serde::Serialize + for<'a> serde::Deserialize<'a> {
60 fn from_second_order(
61 tau: f64,
62 omega: f64,
63 zeta: f64,
64 continuous_bb: Vec<f64>,
65 continuous_cc: Vec<f64>,
66 ) -> Self;
67 fn solve(&mut self, u: &[f64]) -> &[f64];
68} */
69
70impl<S: Default + Solver> UidTuple for DiscreteModalSolver<S> {}
71
72pub trait Get<U: UniqueIdentifier> {
73 fn get(&self) -> Option<Vec<f64>>;
74}
75impl<T, U> Get<U> for DiscreteModalSolver<T>
76where
77 // Vec<Option<gmt_fem::fem_io::Outputs>>: fem_io::FemIo<U>,
78 T: Solver + Default,
79 U: 'static + UniqueIdentifier,
80{
81 fn get(&self) -> Option<Vec<f64>> {
82 let Some(io) = self
83 .outs
84 .iter()
85 .find(|&x| x.as_any().is::<fem_io::SplitFem<U>>())
86 else {
87 panic!(
88 "cannot find {} in DiscreteModalSolver, did you forget to select it?",
89 type_name::<U>()
90 )
91 };
92 Some(self.y[io.range()].to_vec())
93 }
94}
95pub trait Set<U: UniqueIdentifier> {
96 fn set(&mut self, u: &[f64]);
97 fn set_slice(&mut self, _u: &[f64], _range: Range<usize>) {
98 unimplemented!()
99 }
100}
101impl<T, U> Set<U> for DiscreteModalSolver<T>
102where
103 // Vec<Option<gmt_fem::fem_io::Inputs>>: fem_io::FemIo<U>,
104 T: Solver + Default,
105 U: 'static + UniqueIdentifier,
106{
107 fn set(&mut self, u: &[f64]) {
108 let Some(io) = self
109 .ins
110 .iter()
111 .find(|&x| x.as_any().is::<fem_io::SplitFem<U>>())
112 else {
113 panic!(
114 "cannot find {} in DiscreteModalSolver, did you forget to select it?",
115 type_name::<U>()
116 )
117 };
118 if io.len() != u.len() {
119 panic!(
120 "{}: expected {} slice, found {}",
121 type_name::<U>(),
122 io.len(),
123 u.len()
124 );
125 }
126 self.u[io.range()].copy_from_slice(u);
127 }
128 fn set_slice(&mut self, u: &[f64], range: Range<usize>) {
129 if let Some(io) = self
130 .ins
131 .iter()
132 .find(|&x| x.as_any().is::<fem_io::SplitFem<U>>())
133 {
134 self.u[io.range()][range].copy_from_slice(u);
135 }
136 }
137}
138
139#[cfg(feature = "serde")]
140impl<S> interface::filing::Codec for DiscreteModalSolver<S> where
141 S: Solver + Default + serde::ser::Serialize + for<'de> serde::de::Deserialize<'de>
142{
143}