use std::fmt::Debug;
use std::ops::Add;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Sub;
use crate::bins::AngleBin;
use crate::bins::SolidAngleBin;
use crate::convergence::Convergeable;
use nalgebra::Complex;
use rand_distr::num_traits::Pow;
use super::mueller::{Ampl, Mueller};
pub trait ScatteringBin: Clone + Debug {
fn theta_center(&self) -> f32;
fn theta_bin(&self) -> &AngleBin;
fn same_theta(&self, other: &Self) -> bool {
self.theta_bin() == other.theta_bin()
}
}
impl ScatteringBin for SolidAngleBin {
fn theta_center(&self) -> f32 {
self.theta.center
}
fn theta_bin(&self) -> &AngleBin {
&self.theta
}
}
impl ScatteringBin for AngleBin {
fn theta_center(&self) -> f32 {
self.center
}
fn theta_bin(&self) -> &AngleBin {
self
}
}
#[derive(Debug, Clone)]
pub struct ScattResult<B: ScatteringBin> {
pub bin: B,
pub ampl_total: Ampl,
pub ampl_beam: Ampl,
pub ampl_ext: Ampl,
pub mueller_total: Mueller,
pub mueller_beam: Mueller,
pub mueller_ext: Mueller,
}
impl<B: ScatteringBin> Pow<f32> for ScattResult<B> {
type Output = Self;
fn pow(self, rhs: f32) -> Self {
Self {
bin: self.bin,
ampl_total: self.ampl_total.map(|c| c.powf(rhs)),
ampl_beam: self.ampl_beam.map(|c| c.powf(rhs)),
ampl_ext: self.ampl_ext.map(|c| c.powf(rhs)),
mueller_total: self.mueller_total.map(|m| m.powf(rhs)),
mueller_beam: self.mueller_beam.map(|m| m.powf(rhs)),
mueller_ext: self.mueller_ext.map(|m| m.powf(rhs)),
}
}
}
impl<B: ScatteringBin> Mul<f32> for ScattResult<B> {
type Output = Self;
fn mul(self, rhs: f32) -> Self {
Self {
bin: self.bin,
ampl_total: self.ampl_total * Complex::from(rhs),
ampl_beam: self.ampl_beam * Complex::from(rhs),
ampl_ext: self.ampl_ext * Complex::from(rhs),
mueller_total: self.mueller_total * rhs,
mueller_beam: self.mueller_beam * rhs,
mueller_ext: self.mueller_ext * rhs,
}
}
}
impl<B: ScatteringBin> Mul for ScattResult<B> {
type Output = ScattResult<B>;
fn mul(self, other: ScattResult<B>) -> Self::Output {
ScattResult {
bin: self.bin,
ampl_total: self.ampl_total * other.ampl_total,
ampl_beam: self.ampl_beam * other.ampl_beam,
ampl_ext: self.ampl_ext * other.ampl_ext,
mueller_total: self.mueller_total * other.mueller_total,
mueller_beam: self.mueller_beam * other.mueller_beam,
mueller_ext: self.mueller_ext * other.mueller_ext,
}
}
}
impl<B: ScatteringBin> Add for ScattResult<B> {
type Output = ScattResult<B>;
fn add(self, other: ScattResult<B>) -> Self::Output {
ScattResult {
bin: self.bin,
ampl_total: self.ampl_total + other.ampl_total,
ampl_beam: self.ampl_beam + other.ampl_beam,
ampl_ext: self.ampl_ext + other.ampl_ext,
mueller_total: self.mueller_total + other.mueller_total,
mueller_beam: self.mueller_beam + other.mueller_beam,
mueller_ext: self.mueller_ext + other.mueller_ext,
}
}
}
impl<B: ScatteringBin> Sub for ScattResult<B> {
type Output = ScattResult<B>;
fn sub(self, other: ScattResult<B>) -> Self::Output {
ScattResult {
bin: self.bin,
ampl_total: self.ampl_total - other.ampl_total,
ampl_beam: self.ampl_beam - other.ampl_beam,
ampl_ext: self.ampl_ext - other.ampl_ext,
mueller_total: self.mueller_total - other.mueller_total,
mueller_beam: self.mueller_beam - other.mueller_beam,
mueller_ext: self.mueller_ext - other.mueller_ext,
}
}
}
impl<B: ScatteringBin> Div<f32> for ScattResult<B> {
type Output = Self;
fn div(self, other: f32) -> Self {
Self {
bin: self.bin,
ampl_total: self.ampl_total / Complex::from(other),
ampl_beam: self.ampl_beam / Complex::from(other),
ampl_ext: self.ampl_ext / Complex::from(other),
mueller_total: self.mueller_total / other,
mueller_beam: self.mueller_beam / other,
mueller_ext: self.mueller_ext / other,
}
}
}
impl<B: ScatteringBin> Div for ScattResult<B> {
type Output = Self;
fn div(self, other: Self) -> Self {
Self {
bin: self.bin,
ampl_total: self.ampl_total.component_div(&other.ampl_total),
ampl_beam: self.ampl_beam.component_div(&other.ampl_beam),
ampl_ext: self.ampl_ext.component_div(&other.ampl_ext),
mueller_total: self.mueller_total.component_div(&other.mueller_total),
mueller_beam: self.mueller_beam.component_div(&other.mueller_beam),
mueller_ext: self.mueller_ext.component_div(&other.mueller_ext),
}
}
}
impl<B: ScatteringBin> ScattResult<B> {
pub fn new(bin: B) -> Self {
Self {
bin,
ampl_total: Ampl::zeros(),
ampl_beam: Ampl::zeros(),
ampl_ext: Ampl::zeros(),
mueller_total: Mueller::zeros(),
mueller_beam: Mueller::zeros(),
mueller_ext: Mueller::zeros(),
}
}
pub fn ones_like(&self) -> Self {
Self {
bin: self.bin.clone(),
ampl_total: Ampl::from_element(Complex::new(1.0, 0.0)),
ampl_beam: Ampl::from_element(Complex::new(1.0, 0.0)),
ampl_ext: Ampl::from_element(Complex::new(1.0, 0.0)),
mueller_total: Mueller::from_element(1.0),
mueller_beam: Mueller::from_element(1.0),
mueller_ext: Mueller::from_element(1.0),
}
}
}
impl<B: ScatteringBin> Convergeable for ScattResult<B> {
fn zero_like(&self) -> Self {
ScattResult::new(self.bin.clone())
}
fn weighted_add(&self, other: &Self, w1: f32, w2: f32) -> Self {
let total = w1 + w2;
(self.clone() * w1 + other.clone() * w2) / total
}
fn mul_elem(&self, other: &Self) -> Self {
self.clone() * other.clone()
}
fn div_elem(&self, other: &Self) -> Self {
self.clone() / other.clone()
}
fn add_elem(&self, other: &Self) -> Self {
self.clone() + other.clone()
}
fn sub_elem(&self, other: &Self) -> Self {
self.clone() - other.clone()
}
fn scale(&self, scalar: f32) -> Self {
self.clone() * scalar
}
fn sqrt_elem(&self) -> Self {
self.clone().pow(0.5)
}
fn to_weighted(&self) -> Self {
self.clone()
}
fn weights(&self) -> Self {
self.ones_like()
}
}
pub type ScattResult2D = ScattResult<SolidAngleBin>;
pub type ScattResult1D = ScattResult<AngleBin>;