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}