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