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>
{
}