1use crate::utils::{self, Decay, Frame, Sign};
2use rayon::prelude::*;
3use rustitude_core::{convert, prelude::*};
4use sphrs::{ComplexSH, SHEval};
5
6#[derive(Clone)]
7pub struct ThreePiPolFrac<F> {
8 beam_pol: F,
9 j_resonance: u32,
10 p_resonance: F,
11 i_resonance: usize,
12 l_resonance: u32,
13 j_isobar: u32,
14 i_isobar: usize,
15 iz_daughters: [usize; 3],
16 decay_resonance: Decay,
17 decay_isobar: Decay,
18 data: Vec<Complex<F>>,
19}
20
21impl<F: Field> ThreePiPolFrac<F> {
22 #[allow(clippy::too_many_arguments)]
23 pub fn new(
24 beam_pol: Sign,
25 j_resonance: u32,
26 p_resonance: Sign,
27 i_resonance: usize,
28 l_resonance: u32,
29 j_isobar: u32,
30 i_isobar: usize,
31 iz_daughters: [usize; 3],
32 decay_resonance: Decay,
33 decay_isobar: Decay,
34 ) -> Self {
35 match (decay_resonance, decay_isobar) {
36 (Decay::ThreeBodyDecay(_), Decay::TwoBodyDecay(_)) => Self {
37 beam_pol: match beam_pol {
38 Sign::Positive => F::one(),
39 Sign::Negative => -F::one(),
40 },
41 j_resonance,
42 p_resonance: match p_resonance {
43 Sign::Positive => F::one(),
44 Sign::Negative => -F::one(),
45 },
46 i_resonance,
47 l_resonance,
48 j_isobar,
49 i_isobar,
50 iz_daughters,
51 decay_resonance,
52 decay_isobar,
53 data: Vec::default(),
54 },
55 _ => unimplemented!(),
56 }
57 }
58}
59
60impl<F: Field> Node<F> for ThreePiPolFrac<F> {
61 fn calculate(&self, parameters: &[F], event: &Event<F>) -> Result<Complex<F>, RustitudeError> {
62 Ok(self.data[event.index] * (F::one() + self.beam_pol * parameters[0]) / convert!(4, F))
63 }
64
65 fn precalculate(&mut self, dataset: &Dataset<F>) -> Result<(), RustitudeError> {
66 self.data = dataset
67 .events
68 .par_iter()
69 .map(|event| {
70 let isobar_p4 = self.decay_isobar.resonance_p4(event);
71 let resonance_p4 = self.decay_resonance.resonance_p4(event);
72 let alpha = event.recoil_p4.phi();
73 let (_, _, _, p3_res_coords) =
74 self.decay_resonance.coordinates(Frame::Helicity, 2, event);
75 let p1_iso_p4 = self.decay_isobar.primary_p4(event).boost_along(&isobar_p4);
76 let (_, _, _, p1_iso_coords) =
77 Frame::Helicity.coordinates(self.decay_resonance, &p1_iso_p4, event);
78 let k = utils::breakup_momentum(
79 resonance_p4.m(),
80 isobar_p4.m(),
81 self.decay_resonance.tertiary_p4(event).m(),
82 );
83 let q = utils::breakup_momentum(
84 isobar_p4.m(),
85 self.decay_isobar.primary_p4(event).m(),
86 self.decay_isobar.secondary_p4(event).m(),
87 );
88 let neg_res_hel_prod = Complex::new(
89 F::cos(convert!(2, F) * alpha),
90 F::sin(convert!(2, F) * alpha),
91 ) * self.beam_pol
92 * self.p_resonance
93 * convert!(self.j_resonance % 2, F);
94 let mut res = Complex::default();
95 for m_res in -(self.l_resonance as isize)..(self.l_resonance as isize) {
96 let mut term = Complex::default();
97 for m_iso in -(self.j_isobar as isize)..(self.j_isobar as isize) {
98 let ylm = ComplexSH::Spherical.eval(
99 self.j_isobar as i64,
100 m_iso as i64,
101 &p1_iso_coords,
102 );
103 let cg_neg = convert!(
104 wigners::clebsch_gordan(
105 self.j_isobar,
106 self.l_resonance as i32,
107 m_iso as u32,
108 m_res as i32,
109 self.j_resonance,
110 -1,
111 ),
112 F
113 );
114 let cg_pos = convert!(
115 wigners::clebsch_gordan(
116 self.j_isobar,
117 self.l_resonance as i32,
118 m_iso as u32,
119 m_res as i32,
120 self.j_resonance,
121 1,
122 ),
123 F
124 );
125 term += ylm * neg_res_hel_prod * cg_neg + cg_pos;
126 }
127 let ylm = ComplexSH::Spherical.eval(
128 self.l_resonance as i64,
129 m_res as i64,
130 &p3_res_coords,
131 );
132 term *= ylm;
133 res += term;
134 }
135 res *= convert!(
136 wigners::clebsch_gordan(
137 1,
138 1,
139 self.iz_daughters[0] as u32,
140 self.iz_daughters[1] as i32,
141 self.i_isobar as u32,
142 (self.iz_daughters[0] + self.iz_daughters[1]) as i32,
143 ) * wigners::clebsch_gordan(
144 self.i_isobar as u32,
145 1,
146 (self.iz_daughters[0] + self.iz_daughters[1]) as u32,
147 self.iz_daughters[2] as i32,
148 self.i_resonance as u32,
149 (self.iz_daughters[0] + self.iz_daughters[1] + self.iz_daughters[2]) as i32,
150 ),
151 F
152 ) * k.powi(self.l_resonance as i32)
153 * q.powi(self.j_isobar as i32);
154 res
155 })
156 .collect();
157 Ok(())
158 }
159
160 fn parameters(&self) -> Vec<String> {
161 std::vec!["polarization fraction".to_string()]
162 }
163}