use crate::{
builders::{GmtBuilder, GmtModesError, MirrorBuilder},
FromBuilder, Propagation, Source,
};
use ffi::{gmt_m1, gmt_m2, vector};
use std::{
ffi::CStr,
fmt::{Debug, Display},
ops::{Deref, DerefMut},
};
pub type GmtM1 = gmt_m1;
pub type GmtM2 = gmt_m2;
#[derive(Debug, thiserror::Error)]
pub enum GmtError {
#[error(
r#"GMT DOF pattern mismatch, expected:
[None|Some(None|Some(M1((Some(RigidBodyMotions((Some(Txyz(_)),Some(Rxyz(_))))),None|Some(Modes(_)))),
None|Some(M2((Some(RigidBodyMotions((Some(Txyz(_)),Some(Rxyz(_))))),None|Some(Modes(_)))))));7]
"#
)]
GmtDofMatch,
#[error("invalid SegmentDof pattern")]
SegmentDof,
#[error("mirror modes file not found")]
Modes(#[from] GmtModesError),
}
pub trait GmtMx {
fn modes_as_mut(&mut self) -> &mut ffi::modes;
fn update(&mut self, origin_: vector, euler_angles_: vector, idx: ::std::os::raw::c_int);
}
impl GmtMx for gmt_m1 {
#[inline]
fn modes_as_mut(&mut self) -> &mut ffi::modes {
&mut self.BS
}
#[inline]
fn update(&mut self, origin_: vector, euler_angles_: vector, idx: ::std::os::raw::c_int) {
unsafe { self.update(origin_, euler_angles_, idx) }
}
}
impl GmtMx for gmt_m2 {
#[inline]
fn modes_as_mut(&mut self) -> &mut ffi::modes {
&mut self.BS
}
#[inline]
fn update(&mut self, origin_: vector, euler_angles_: vector, idx: ::std::os::raw::c_int) {
unsafe { self.update(origin_, euler_angles_, idx) }
}
}
pub trait MirrorGetSet {
fn set_modes(&mut self, a: &[f64]) -> &mut Self;
fn set_segment_modes(&mut self, sid: u8, a: &[f64]) -> &mut Self;
fn set_rigid_body_motions(&mut self, sid: u8, tr_xyz: &[f64]) -> &mut Self;
}
impl<M: GmtMx> MirrorGetSet for Mirror<M> {
fn set_segment_modes(&mut self, sid: u8, a: &[f64]) -> &mut Self {
self.a
.chunks_mut(self.n_mode)
.skip(sid as usize - 1)
.take(1)
.for_each(|a_sid: &mut [f64]| {
a_sid.iter_mut().zip(a).for_each(|(a_sid, a)| *a_sid = *a)
});
unsafe {
let m_sid_a = self.a.as_mut_ptr();
self._c_.modes_as_mut().update(m_sid_a);
}
self
}
fn set_modes(&mut self, a: &[f64]) -> &mut Self {
let a_n_mode = a.len() / 7;
self.a
.chunks_mut(self.n_mode)
.zip(a.chunks(a_n_mode))
.for_each(|(a_sid, a)| a_sid.iter_mut().zip(a).for_each(|(a_sid, a)| *a_sid = *a));
unsafe {
let m_sid_a = self.a.as_mut_ptr();
self.modes_as_mut().update(m_sid_a);
}
self
}
fn set_rigid_body_motions(&mut self, sid: u8, tr_xyz: &[f64]) -> &mut Self {
assert!(sid > 0 && sid < 8, "Segment ID must be in the range [1,7]!");
let t_xyz = vector {
x: tr_xyz[0],
y: tr_xyz[1],
z: tr_xyz[2],
};
let r_xyz = vector {
x: tr_xyz[3],
y: tr_xyz[4],
z: tr_xyz[5],
};
self.update(t_xyz, r_xyz, sid as i32);
self
}
}
#[derive(Debug, Default)]
pub struct Mirror<M: GmtMx> {
pub _c_: M,
pub mode_type: String,
pub n_mode: usize,
pub a: Vec<f64>,
}
impl<M: GmtMx + Display> Display for Mirror<M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} ({},{})", self._c_, self.mode_type, self.n_mode)
}
}
impl<M: GmtMx + Default> From<MirrorBuilder> for Mirror<M> {
fn from(builder: MirrorBuilder) -> Self {
Self {
_c_: Default::default(),
mode_type: builder.mode_type,
n_mode: builder.n_mode,
a: builder.a,
}
}
}
impl<M: GmtMx> Deref for Mirror<M> {
type Target = M;
fn deref(&self) -> &Self::Target {
&self._c_
}
}
impl<M: GmtMx> DerefMut for Mirror<M> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self._c_
}
}
pub trait GmtMirror<M: GmtMx> {
fn as_mut(&mut self) -> &mut Mirror<M>;
fn to_string(&self) -> String;
}
impl GmtMirror<gmt_m1> for Gmt {
fn as_mut(&mut self) -> &mut Mirror<gmt_m1> {
&mut self.m1
}
fn to_string(&self) -> String {
self.m1._c_.to_string()
}
}
impl GmtMirror<gmt_m2> for Gmt {
fn as_mut(&mut self) -> &mut Mirror<gmt_m2> {
&mut self.m2
}
fn to_string(&self) -> String {
self.m2._c_.to_string()
}
}
pub struct Gmt {
pub m1: Mirror<gmt_m1>,
pub m2: Mirror<gmt_m2>,
pub pointing_error: Option<(f64, f64)>,
pub(crate) m1_truss_projection: bool,
}
impl Display for Gmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.m1_truss_projection {
writeln!(f, "GMT: {}, {}", self.m1, self.m2)?;
} else {
writeln!(f, "GMT (no trusses): {}, {}", self.m1, self.m2)?;
};
Ok(())
}
}
impl FromBuilder for Gmt {
type ComponentBuilder = GmtBuilder;
}
impl Gmt {
pub fn get_m1_mode_type(&self) -> String {
unsafe {
String::from(
CStr::from_ptr(self.m1.BS.filename.as_ptr())
.to_str()
.expect("CStr::to_str failed"),
)
}
}
pub fn get_m1(&self) -> MirrorBuilder {
MirrorBuilder {
mode_type: self.get_m1_mode_type(),
n_mode: self.m1.n_mode,
a: self.m1.a.clone(),
}
}
pub fn get_m2(&self) -> MirrorBuilder {
MirrorBuilder {
mode_type: self.get_m2_mode_type(),
n_mode: self.m2.n_mode,
a: self.m2.a.clone(),
}
}
pub fn get_m2_mode_type(&self) -> String {
unsafe {
String::from(
CStr::from_ptr(self.m2.BS.filename.as_ptr())
.to_str()
.expect("CStr::to_str failed"),
)
}
}
pub fn reset(&mut self) -> &mut Self {
unsafe {
self.m1.reset();
self.m2.reset();
let a = self.m1.a.as_mut_ptr();
self.m1.BS.update(a);
let a = self.m2.a.as_mut_ptr();
self.m2.BS.update(a);
}
self
}
pub fn keep(&mut self, sid: &[i32]) -> &mut Self {
unsafe {
self.m1.keep(sid.as_ptr() as *mut _, sid.len() as i32);
self.m2.keep(sid.as_ptr() as *mut _, sid.len() as i32);
}
self
}
pub fn m1_segment_state(&mut self, sid: i32, t_xyz: &[f64], r_xyz: &[f64]) {
assert!(
sid > 0 && sid < 8,
"segment ID ({sid}) must be in the range [1,7]!"
);
let t_xyz = vector {
x: t_xyz[0],
y: t_xyz[1],
z: t_xyz[2],
};
let r_xyz = vector {
x: r_xyz[0],
y: r_xyz[1],
z: r_xyz[2],
};
unsafe {
self.m1.update(t_xyz, r_xyz, sid);
}
}
pub fn m2_segment_state(&mut self, sid: i32, t_xyz: &[f64], r_xyz: &[f64]) {
let t_xyz = vector {
x: t_xyz[0],
y: t_xyz[1],
z: t_xyz[2],
};
let r_xyz = vector {
x: r_xyz[0],
y: r_xyz[1],
z: r_xyz[2],
};
unsafe {
self.m2.update(t_xyz, r_xyz, sid);
}
}
pub fn m1_modes(&mut self, a: &[f64]) {
let a_n_mode = a.len() / 7;
self.m1
.a
.chunks_mut(self.m1.n_mode)
.zip(a.chunks(a_n_mode))
.for_each(|(a1, a)| a1.iter_mut().zip(a).for_each(|(a1, a)| *a1 = *a));
unsafe {
let m1_a = self.m1.a.as_mut_ptr();
self.m1.BS.update(m1_a);
}
}
pub fn m1_segment_modes(&mut self, sid: u8, a: &[f64]) {
self.m1
.a
.chunks_mut(self.m1.n_mode)
.skip(sid as usize - 1)
.take(1)
.for_each(|a1| a1.iter_mut().zip(a).for_each(|(a1, a)| *a1 = *a));
unsafe {
let m1_a = self.m1.a.as_mut_ptr();
self.m1.BS.update(m1_a);
}
}
pub fn m1_modes_ij(&mut self, i: usize, j: usize, value: f64) {
let mut a = vec![0f64; 7 * self.m1.n_mode];
a[i * self.m1.n_mode + j] = value;
unsafe {
self.m1.BS.update(a.as_mut_ptr());
}
}
pub fn m2_modes(&mut self, a: &[f64]) {
let a_n_mode = a.len() / 7;
self.m2
.a
.chunks_mut(self.m2.n_mode)
.zip(a.chunks(a_n_mode))
.for_each(|(a2, a)| a2.iter_mut().zip(a).for_each(|(a2, a)| *a2 = *a));
unsafe {
let m2_a = self.m2.a.as_mut_ptr();
self.m2.BS.update(m2_a);
}
}
pub fn m2_segment_modes(&mut self, sid: u8, a: &[f64]) {
self.m2
.a
.chunks_mut(self.m2.n_mode)
.skip(sid as usize - 1)
.take(1)
.for_each(|a2| a2.iter_mut().zip(a).for_each(|(a2, a)| *a2 = *a));
unsafe {
let m2_a = self.m2.a.as_mut_ptr();
self.m2.BS.update(m2_a);
}
}
pub fn m2_modes_ij(&mut self, i: usize, j: usize, value: f64) {
let mut a = vec![0f64; 7 * self.m2.n_mode];
a[i * self.m2.n_mode + j] = value;
unsafe {
self.m2.BS.update(a.as_mut_ptr());
}
}
pub fn update(
&mut self,
m1_rbm: Option<&Vec<Vec<f64>>>,
m2_rbm: Option<&Vec<Vec<f64>>>,
m1_mode: Option<&Vec<Vec<f64>>>,
m2_mode: Option<&Vec<Vec<f64>>>,
) {
if let Some(m1_rbm) = m1_rbm {
for (k, rbm) in m1_rbm.iter().enumerate() {
self.m1_segment_state((k + 1) as i32, &rbm[..3], &rbm[3..]);
}
}
if let Some(m2_rbm) = m2_rbm {
for (k, rbm) in m2_rbm.iter().enumerate() {
self.m2_segment_state((k + 1) as i32, &rbm[..3], &rbm[3..]);
}
}
if let Some(m1_mode) = m1_mode {
let mut m = m1_mode.clone().into_iter().flatten().collect::<Vec<f64>>();
self.m1_modes(&mut m);
}
if let Some(m2_mode) = m2_mode {
let mut m = m2_mode.clone().into_iter().flatten().collect::<Vec<f64>>();
self.m2_modes(&mut m);
}
}
pub fn update42(
&mut self,
m1_rbm: Option<&[f64]>,
m2_rbm: Option<&[f64]>,
m1_mode: Option<&[f64]>,
m2_mode: Option<&[f64]>,
) {
if let Some(m1_rbm) = m1_rbm {
for (k, rbm) in m1_rbm.chunks(6).enumerate() {
self.m1_segment_state((k + 1) as i32, &rbm[..3], &rbm[3..]);
}
}
if let Some(m2_rbm) = m2_rbm {
for (k, rbm) in m2_rbm.chunks(6).enumerate() {
self.m2_segment_state((k + 1) as i32, &rbm[..3], &rbm[3..]);
}
}
if let Some(m1_mode) = m1_mode {
let mut m = m1_mode.to_vec();
self.m1_modes(&mut m);
}
if let Some(m2_mode) = m2_mode {
let mut m = m2_mode.to_vec();
self.m2_modes(&mut m);
}
}
pub fn trace_all(&mut self, src: &mut Source) -> &mut Self {
unsafe {
src.as_raw_mut_ptr().reset_rays();
let rays = &mut src.as_raw_mut_ptr().rays;
self.m1.traceall(rays);
self.m2.traceall(rays);
rays.to_sphere1(-5.830, 2.197173);
}
self
}
}
impl Drop for Gmt {
fn drop(&mut self) {
unsafe {
self.m1.cleanup();
self.m2.cleanup();
}
}
}
impl Propagation for Gmt {
fn propagate(&mut self, src: &mut Source) {
if let Some((pz, pa)) = self.pointing_error {
let (s, c) = pa.sin_cos();
let (px, py) = (pz * c, pz * s);
let (zenith, azimuth): (Vec<_>, Vec<_>) = src
.zenith
.iter()
.map(|z| *z as f64)
.zip(src.azimuth.iter().map(|a| *a as f64))
.map(|(z, a)| {
let (s, c) = a.sin_cos();
(z * c - px, z * s - py)
})
.map(|(x, y)| (x.hypot(y), y.atan2(x)))
.unzip();
src.update(zenith, azimuth);
unsafe {
src.as_raw_mut_ptr().reset_rays();
let rays = &mut src.as_raw_mut_ptr().rays;
self.m2.blocking(rays);
self.m1.trace(rays);
if self.m1_truss_projection {
rays.gmt_truss_onaxis();
}
rays.gmt_m2_baffle();
self.m2.trace(rays);
rays.to_sphere1(-5.830, 2.197173);
}
src.update(
src.zenith.iter().map(|x| *x as f64).collect(),
src.azimuth.iter().map(|x| *x as f64).collect(),
);
} else {
unsafe {
src.as_raw_mut_ptr().reset_rays();
let rays = &mut src.as_raw_mut_ptr().rays;
self.m2.blocking(rays);
self.m1.trace(rays);
if self.m1_truss_projection {
rays.gmt_truss_onaxis();
}
rays.gmt_m2_baffle();
self.m2.trace(rays);
rays.to_sphere1(-5.830, 2.197173);
}
}
}
fn time_propagate(&mut self, _secs: f64, src: &mut Source) {
self.propagate(src)
}
}