use super::{binning, shift_and_add};
use crate::{Field, Intensity, Observer, Observing, ObservingModes};
use indicatif::ProgressBar;
use rand_distr::{Distribution, Poisson};
impl<T, Mode> Field<T, Mode>
where
T: Observer,
Mode: ObservingModes + Send,
Observing<Mode>: Intensity,
{
pub fn intensity(&mut self, bar: Option<ProgressBar>) -> Vec<f64> {
let b = self
.pixel_scale
.to_nyquist_clamped_ratio(&self.observer, &self.photometry);
let intensity_sampling = (b * self.field_of_view.to_pixelscale_ratio(self)).ceil() as usize;
let pupil_size = b * self.photometry.wavelength / self.resolution();
let mut n_dft = (pupil_size / self.observer.resolution()).ceil() as usize;
if intensity_sampling > n_dft && intensity_sampling % 2 != n_dft % 2 {
n_dft += 1;
}
log::debug!(
r"
. Image sampling: {intensity_sampling}:{b}
. Pupil size : {pupil_size:.3}m
. DFT sampling : {n_dft}
"
);
let mut buffer = vec![0f64; intensity_sampling.pow(2)];
let n = intensity_sampling as i32;
let alpha = self.resolution() / b;
let mut rng = rand::thread_rng();
for star in self.objects.iter() {
bar.as_ref().map(|b| b.inc(1));
if !star.inside_box(self.field_of_view() + self.resolution() * 2.) {
continue;
}
let n_photon = self.flux.unwrap_or(
self.photometry.n_photon(star.magnitude)
* self.exposure
* self.observer.resolution().powi(2), );
let (x, y) = star.coordinates;
let x0 = -(y / alpha).round();
let y0 = (x / alpha).round();
let fr_x0 = -y.to_radians() - x0 * alpha;
let fr_y0 = x.to_radians() - y0 * alpha;
let shift = if intensity_sampling % 2 == 0 {
Some((
0.5 / pupil_size + fr_x0 / self.photometry.wavelength,
0.5 / pupil_size + fr_y0 / self.photometry.wavelength,
))
} else {
Some((
fr_x0 / self.photometry.wavelength,
fr_y0 / self.photometry.wavelength,
))
};
self.observing_mode
.init_fft(n_dft, self.observer.resolution());
let mut pupil = self.observer.pupil(shift);
pupil.iter_mut().for_each(|p| *p *= n_photon.sqrt());
let mut intensity = self
.observing_mode
.intensity(pupil, intensity_sampling, star)
.unwrap();
log::debug!("Image flux: {n_photon}");
if self.poisson_noise {
intensity.iter_mut().for_each(|i| {
if *i == 0f64 {
*i = 0f64;
} else {
let poi = Poisson::new(*i).unwrap();
*i = poi.sample(&mut rng)
}
})
};
shift_and_add(buffer.as_mut_slice(), x0, y0, n, intensity);
}
bar.as_ref().map(|b| b.finish());
self.intensity_sampling = Some(intensity_sampling);
let m = b as usize;
if m == 1 {
return buffer;
}
binning(intensity_sampling, m, buffer)
}
}