use crate::builders::ImagingBuilder;
use crate::{Cu, FromBuilder};
use super::Propagation;
use super::Source;
use ffi::{dev2host, imaging};
use serde::Deserialize;
use serde::Serialize;
use std::f32;
use std::fmt::Display;
use crate::cu::Single;
#[derive(Debug, Clone, PartialEq, Copy, Serialize, Deserialize)]
pub struct LensletArray {
pub n_side_lenslet: usize,
pub n_px_lenslet: usize,
pub d: f64,
}
impl Default for LensletArray {
fn default() -> Self {
LensletArray {
n_side_lenslet: 1,
n_px_lenslet: 511,
d: 25.5,
}
}
}
impl LensletArray {
pub fn n_side_lenslet(self, n_side_lenslet: usize) -> Self {
let d = self.d * self.n_side_lenslet as f64 / n_side_lenslet as f64;
Self {
n_side_lenslet,
d,
..self
}
}
pub fn n_px_lenslet(self, n_px_lenslet: usize) -> Self {
Self {
n_px_lenslet,
..self
}
}
pub fn pitch(self, d: f64) -> Self {
Self { d, ..self }
}
}
#[derive(Debug, Clone, PartialEq, Copy, Serialize, Deserialize)]
pub struct Detector {
pub n_px_framelet: usize,
pub n_px_imagelet: Option<usize>,
pub osf: usize,
pub noise_specs: Option<NoiseDataSheet>,
}
impl Default for Detector {
fn default() -> Self {
Detector {
n_px_framelet: 512,
n_px_imagelet: None,
osf: 2,
noise_specs: None,
}
}
}
impl Detector {
pub fn n_px_framelet(self, n_px_framelet: usize) -> Self {
Self {
n_px_framelet,
..self
}
}
pub fn n_px_imagelet(self, n_px_imagelet: usize) -> Self {
Self {
n_px_imagelet: Some(n_px_imagelet),
..self
}
}
pub fn osf(self, osf: usize) -> Self {
Self { osf, ..self }
}
pub fn noise_specs(self, noise_specs: NoiseDataSheet) -> Self {
Self {
noise_specs: Some(noise_specs),
..self
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct NoiseDataSheet {
pub exposure_time: f64,
pub rms_read_out_noise: f64,
pub n_background_photon: f64,
pub noise_factor: f64,
}
impl NoiseDataSheet {
pub fn new(exposure_time: f64) -> Self {
Self {
exposure_time,
..Default::default()
}
}
pub fn read_out(self, rms_read_out_noise: f64) -> Self {
NoiseDataSheet {
rms_read_out_noise,
..self
}
}
pub fn background(self, n_background_photon: f64) -> Self {
NoiseDataSheet {
n_background_photon,
..self
}
}
pub fn excess_noise(self, noise_factor: f64) -> Self {
NoiseDataSheet {
noise_factor,
..self
}
}
}
impl Default for NoiseDataSheet {
fn default() -> Self {
NoiseDataSheet {
exposure_time: 1f64,
rms_read_out_noise: 0f64,
n_background_photon: 0f64,
noise_factor: 1f64,
}
}
}
#[derive(Clone, Default)]
pub struct Frame {
pub dev: Cu<Single>,
pub n_px_camera: usize,
pub resolution: usize,
pub n_frame: usize,
pub idx: usize,
}
impl From<&mut Frame> for Vec<f32> {
fn from(value: &mut Frame) -> Self {
value.dev.from_dev()
}
}
impl From<&Frame> for Vec<f32> {
fn from(value: &Frame) -> Self {
let mut dev = Cu::<Single>::vector(value.dev.size());
dev.from_ptr(value.dev.as_ptr() as *mut _);
dev.from_dev()
}
}
impl From<Frame> for Vec<f32> {
fn from(mut value: Frame) -> Self {
value.dev.from_dev()
}
}
impl From<Vec<f32>> for Frame {
fn from(value: Vec<f32>) -> Self {
let n = value.len();
let sqrt_n = (n as f64).sqrt() as usize;
assert_eq!(n, sqrt_n * sqrt_n, "the frame is not square");
Self {
dev: Cu::<Single>::from(value),
n_px_camera: sqrt_n,
resolution: sqrt_n,
n_frame: 1,
idx: 1,
}
}
}
impl Frame {
pub fn new(data: Vec<f32>, resolution: usize, n_px_camera: usize) -> Self {
Self {
dev: Cu::<Single>::from(data),
n_px_camera,
resolution,
n_frame: 1,
idx: 1,
}
}
pub fn is_empty(&self) -> bool {
self.idx == 0
}
pub fn roi(&self) -> (usize, usize) {
(self.resolution, self.resolution)
}
}
pub struct Imaging {
pub(crate) _c_: imaging,
pub(crate) dft_osf: usize,
pub fluxlet_threshold: f64,
}
impl FromBuilder for Imaging {
type ComponentBuilder = ImagingBuilder;
}
impl Imaging {
pub fn new() -> Imaging {
Imaging {
_c_: Default::default(),
dft_osf: 1,
fluxlet_threshold: 0.,
}
}
pub fn __ceo__(&self) -> &imaging {
&self._c_
}
pub fn frame_transfer(&mut self, frame: &mut Vec<f32>) -> &mut Self {
unsafe {
dev2host(
frame.as_mut_ptr(),
self._c_.d__frame,
self.resolution() * self.resolution() * self._c_.N_SOURCE,
);
}
self
}
pub fn frame(&self) -> Frame {
let mut cu = Cu::<Single>::vector(
(self.resolution() * self.resolution() * self._c_.N_SOURCE) as usize,
);
cu.from_ptr(self._c_.d__frame);
Frame {
dev: cu,
n_px_camera: self._c_.N_PX_CAMERA as usize,
resolution: self.resolution() as usize,
n_frame: self._c_.N_SOURCE as usize,
idx: self._c_.N_FRAME as usize,
}
}
pub fn reset(&mut self) -> &mut Self {
unsafe {
self._c_.reset();
}
self
}
pub fn resolution(&self) -> i32 {
self._c_.N_PX_CAMERA * self._c_.N_SIDE_LENSLET
}
pub fn n_frame(&self) -> u32 {
self._c_.N_FRAME as u32
}
pub fn readout(
&mut self,
exposure: f64,
detector_noise_properties: Option<NoiseDataSheet>,
) -> &mut Self {
detector_noise_properties.map_or_else(
|| (),
|p| unsafe {
self._c_.readout1(
exposure as f32,
p.rms_read_out_noise as f32,
p.n_background_photon as f32,
p.noise_factor as f32,
);
},
);
self
}
pub fn pixel_scale(&self, src: &Source) -> f32 {
(src.wavelength() / src.pupil_size / self.dft_osf as f64) as f32
* (self._c_.N_SIDE_LENSLET * self._c_.BIN_IMAGE) as f32
}
pub fn field_of_view(&self, src: &Source) -> f32 {
self.pixel_scale(src) * (self._c_.N_PX_CAMERA as f32)
}
pub fn pointing(
&mut self,
xy: &[(f64, f64)],
src: &Source, ) -> &mut Self {
unsafe {
assert_eq!(xy.len(), src.size as usize);
let za = src.zenith.iter().zip(&src.azimuth);
let (mut zen, mut azi): (Vec<_>, Vec<_>) = xy
.iter()
.zip(za)
.map(|((x, y), (&z, a))| {
let (sa, ca) = a.sin_cos();
let (x, y) = (*x as f32 + z * ca, *y as f32 + z * sa);
(x.hypot(y), y.atan2(x))
})
.unzip();
self._c_.pixel_scale = (src.wavelength() / src.pupil_size / self.dft_osf as f64) as f32
* (self._c_.N_SIDE_LENSLET) as f32;
self._c_.absolute_pointing = 1;
self._c_
.set_pointing_direction(zen.as_mut_ptr(), azi.as_mut_ptr());
}
self
}
pub fn n_guide_star(&self) -> i32 {
self._c_.N_SOURCE
}
}
impl Display for Imaging {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
"Imaging (x{}): {}x{} lenslets, {}x{} pixels, osf {}, {}x{} binning",
self._c_.N_SOURCE,
self._c_.N_SIDE_LENSLET,
self._c_.N_SIDE_LENSLET,
self._c_.N_PX_CAMERA,
self._c_.N_PX_CAMERA,
self.dft_osf,
self._c_.BIN_IMAGE,
self._c_.BIN_IMAGE
)
}
}
impl Drop for Imaging {
fn drop(&mut self) {
unsafe {
self._c_.cleanup();
}
}
}
impl Propagation for Imaging {
fn propagate(&mut self, src: &mut Source) {
unsafe {
self._c_.propagate(src.as_raw_mut_ptr());
}
}
fn time_propagate(&mut self, _secs: f64, src: &mut Source) {
self.propagate(src)
}
}