1use super::boc::Order;
4use super::convolutions::{Convolution, LumiCache};
5use super::grid::{Grid, GridError};
6use super::subgrid::Subgrid;
7use float_cmp::approx_eq;
8use ndarray::Array4;
9use std::collections::HashMap;
10use std::fmt::{self, Display, Formatter};
11use std::io::Write;
12use std::str::FromStr;
13use thiserror::Error;
14
15#[repr(transparent)]
27pub struct FkTable {
28 grid: Grid,
29}
30
31#[derive(Debug, Error)]
33pub enum TryFromGridError {
34 #[error("multiple scales detected")]
36 MultipleScales,
37 #[error("complicated channel function detected")]
39 InvalidChannel,
40 #[error("multiple orders detected")]
42 NonTrivialOrder,
43}
44
45#[derive(Debug, Clone, Copy, Eq, PartialEq)]
50pub enum FkAssumptions {
51 Nf6Ind,
53 Nf6Sym,
56 Nf5Ind,
59 Nf5Sym,
62 Nf4Ind,
65 Nf4Sym,
69 Nf3Ind,
72 Nf3Sym,
75}
76
77#[derive(Debug, Eq, Error, PartialEq)]
79#[error("unknown variant for FkAssumptions: {variant}")]
80pub struct UnknownFkAssumption {
81 variant: String,
82}
83
84impl Display for FkAssumptions {
85 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
86 write!(
87 f,
88 "{}",
89 match self {
90 Self::Nf6Ind => "Nf6Ind",
91 Self::Nf6Sym => "Nf6Sym",
92 Self::Nf5Ind => "Nf5Ind",
93 Self::Nf5Sym => "Nf5Sym",
94 Self::Nf4Ind => "Nf4Ind",
95 Self::Nf4Sym => "Nf4Sym",
96 Self::Nf3Ind => "Nf3Ind",
97 Self::Nf3Sym => "Nf3Sym",
98 }
99 )
100 }
101}
102
103impl FromStr for FkAssumptions {
104 type Err = UnknownFkAssumption;
105
106 fn from_str(s: &str) -> Result<Self, Self::Err> {
107 Ok(match s {
108 "Nf6Ind" => Self::Nf6Ind,
109 "Nf6Sym" => Self::Nf6Sym,
110 "Nf5Ind" => Self::Nf5Ind,
111 "Nf5Sym" => Self::Nf5Sym,
112 "Nf4Ind" => Self::Nf4Ind,
113 "Nf4Sym" => Self::Nf4Sym,
114 "Nf3Ind" => Self::Nf3Ind,
115 "Nf3Sym" => Self::Nf3Sym,
116 _ => {
117 return Err(UnknownFkAssumption {
118 variant: s.to_owned(),
119 });
120 }
121 })
122 }
123}
124
125impl FkTable {
126 #[must_use]
128 pub const fn grid(&self) -> &Grid {
129 &self.grid
130 }
131
132 #[must_use]
138 pub fn into_grid(self) -> Grid {
139 self.grid
140 }
141
142 #[must_use]
149 pub fn table(&self) -> Array4<f64> {
150 let has_pdf1 = self.grid.convolutions()[0] != Convolution::None;
151 let has_pdf2 = self.grid.convolutions()[1] != Convolution::None;
152 let x_grid = self.x_grid();
153
154 let mut result = Array4::zeros((
155 self.bins(),
156 self.grid.channels().len(),
157 if has_pdf1 { x_grid.len() } else { 1 },
158 if has_pdf2 { x_grid.len() } else { 1 },
159 ));
160
161 for ((_, bin, channel), subgrid) in self.grid().subgrids().indexed_iter() {
162 let indices1 = if has_pdf1 {
163 subgrid
164 .x1_grid()
165 .iter()
166 .map(|&s| x_grid.iter().position(|&x| approx_eq!(f64, s, x, ulps = 2)))
167 .collect::<Option<_>>()
168 .unwrap()
169 } else {
170 vec![0]
171 };
172 let indices2 = if has_pdf2 {
173 subgrid
174 .x2_grid()
175 .iter()
176 .map(|&s| x_grid.iter().position(|&x| approx_eq!(f64, s, x, ulps = 2)))
177 .collect::<Option<_>>()
178 .unwrap()
179 } else {
180 vec![0]
181 };
182
183 for ((_, ix1, ix2), value) in subgrid.indexed_iter() {
184 result[[bin, channel, indices1[ix1], indices2[ix2]]] = value;
185 }
186 }
187
188 result
189 }
190
191 #[must_use]
193 pub fn bins(&self) -> usize {
194 self.grid.bin_info().bins()
195 }
196
197 #[must_use]
199 pub fn bin_normalizations(&self) -> Vec<f64> {
200 self.grid.bin_info().normalizations()
201 }
202
203 #[must_use]
205 pub fn bin_dimensions(&self) -> usize {
206 self.grid.bin_info().dimensions()
207 }
208
209 #[must_use]
211 pub fn bin_left(&self, dimension: usize) -> Vec<f64> {
212 self.grid.bin_info().left(dimension)
213 }
214
215 #[must_use]
217 pub fn bin_right(&self, dimension: usize) -> Vec<f64> {
218 self.grid.bin_info().right(dimension)
219 }
220
221 #[must_use]
223 pub const fn key_values(&self) -> Option<&HashMap<String, String>> {
224 self.grid.key_values()
225 }
226
227 #[must_use]
229 pub fn channels(&self) -> Vec<(i32, i32)> {
230 self.grid
231 .channels()
232 .iter()
233 .map(|entry| (entry.entry()[0].0, entry.entry()[0].1))
234 .collect()
235 }
236
237 #[must_use]
239 pub fn muf2(&self) -> f64 {
240 if let &[muf2] = &self.grid.evolve_info(&[true]).fac1[..] {
241 muf2
242 } else {
243 unreachable!()
245 }
246 }
247
248 #[must_use]
250 pub fn x_grid(&self) -> Vec<f64> {
251 self.grid.evolve_info(&[true]).x1
252 }
253
254 pub fn write(&self, writer: impl Write) -> Result<(), GridError> {
260 self.grid.write(writer)
261 }
262
263 pub fn write_lz4(&self, writer: impl Write) -> Result<(), GridError> {
269 self.grid.write_lz4(writer)
270 }
271
272 pub fn convolve(
275 &self,
276 lumi_cache: &mut LumiCache,
277 bin_indices: &[usize],
278 channel_mask: &[bool],
279 ) -> Vec<f64> {
280 self.grid
281 .convolve(lumi_cache, &[], bin_indices, channel_mask, &[(1.0, 1.0)])
282 }
283
284 pub fn set_key_value(&mut self, key: &str, value: &str) {
286 self.grid.set_key_value(key, value);
287 }
288
289 pub fn optimize(&mut self, assumptions: FkAssumptions) {
296 let mut add = Vec::new();
297
298 match assumptions {
299 FkAssumptions::Nf6Ind => {
300 }
302 FkAssumptions::Nf6Sym => {
303 add.push((235, 200));
304 }
305 FkAssumptions::Nf5Ind => {
306 add.extend_from_slice(&[(235, 200), (135, 100)]);
307 }
308 FkAssumptions::Nf5Sym => {
309 add.extend_from_slice(&[(235, 200), (135, 100), (224, 200)]);
310 }
311 FkAssumptions::Nf4Ind => {
312 add.extend_from_slice(&[(235, 200), (135, 100), (224, 200), (124, 100)]);
313 }
314 FkAssumptions::Nf4Sym => {
315 add.extend_from_slice(&[
316 (235, 200),
317 (135, 100),
318 (224, 200),
319 (124, 100),
320 (215, 200),
321 ]);
322 }
323 FkAssumptions::Nf3Ind => {
324 add.extend_from_slice(&[
325 (235, 200),
326 (135, 100),
327 (224, 200),
328 (124, 100),
329 (215, 200),
330 (115, 100),
331 ]);
332 }
333 FkAssumptions::Nf3Sym => {
334 add.extend_from_slice(&[
335 (235, 200),
336 (135, 100),
337 (224, 200),
338 (124, 100),
339 (215, 200),
340 (115, 100),
341 (208, 200),
342 ]);
343 }
344 }
345
346 self.grid.rewrite_channels(&add, &[]);
347
348 self.grid
350 .set_key_value("fk_assumptions", &assumptions.to_string());
351 self.grid.optimize();
352 }
353}
354
355impl TryFrom<Grid> for FkTable {
356 type Error = TryFromGridError;
357
358 fn try_from(grid: Grid) -> Result<Self, Self::Error> {
359 let mut muf2 = -1.0;
360
361 if grid.orders()
362 != [Order {
363 alphas: 0,
364 alpha: 0,
365 logxir: 0,
366 logxif: 0,
367 }]
368 {
369 return Err(TryFromGridError::NonTrivialOrder);
370 }
371
372 for subgrid in grid.subgrids() {
373 if subgrid.is_empty() {
374 continue;
375 }
376
377 let mu2_grid = subgrid.mu2_grid();
378
379 if mu2_grid.len() > 1 {
380 return Err(TryFromGridError::MultipleScales);
381 }
382
383 if muf2 < 0.0 {
384 muf2 = mu2_grid[0].fac;
385 } else if muf2 != mu2_grid[0].fac {
386 return Err(TryFromGridError::MultipleScales);
387 }
388 }
389
390 for channel in grid.channels() {
391 let entry = channel.entry();
392
393 if entry.len() != 1 || entry[0].2 != 1.0 {
394 return Err(TryFromGridError::InvalidChannel);
395 }
396 }
397
398 if (1..grid.channels().len())
399 .any(|i| grid.channels()[i..].contains(&grid.channels()[i - 1]))
400 {
401 return Err(TryFromGridError::InvalidChannel);
402 }
403
404 Ok(Self { grid })
405 }
406}
407
408#[cfg(test)]
409mod tests {
410 use super::*;
411
412 #[test]
413 fn fk_assumptions_try_from() {
414 assert_eq!(FkAssumptions::from_str("Nf6Ind"), Ok(FkAssumptions::Nf6Ind));
415 assert_eq!(FkAssumptions::from_str("Nf6Sym"), Ok(FkAssumptions::Nf6Sym));
416 assert_eq!(FkAssumptions::from_str("Nf5Ind"), Ok(FkAssumptions::Nf5Ind));
417 assert_eq!(FkAssumptions::from_str("Nf5Sym"), Ok(FkAssumptions::Nf5Sym));
418 assert_eq!(FkAssumptions::from_str("Nf4Ind"), Ok(FkAssumptions::Nf4Ind));
419 assert_eq!(FkAssumptions::from_str("Nf4Sym"), Ok(FkAssumptions::Nf4Sym));
420 assert_eq!(FkAssumptions::from_str("Nf3Ind"), Ok(FkAssumptions::Nf3Ind));
421 assert_eq!(FkAssumptions::from_str("Nf3Sym"), Ok(FkAssumptions::Nf3Sym));
422 assert_eq!(
423 FkAssumptions::from_str("XXXXXX"),
424 Err(UnknownFkAssumption {
425 variant: "XXXXXX".to_owned()
426 })
427 );
428 }
429
430 #[test]
431 fn fk_assumptions_display() {
432 assert_eq!(format!("{}", FkAssumptions::Nf6Ind), "Nf6Ind");
433 assert_eq!(format!("{}", FkAssumptions::Nf6Sym), "Nf6Sym");
434 assert_eq!(format!("{}", FkAssumptions::Nf5Ind), "Nf5Ind");
435 assert_eq!(format!("{}", FkAssumptions::Nf5Sym), "Nf5Sym");
436 assert_eq!(format!("{}", FkAssumptions::Nf4Ind), "Nf4Ind");
437 assert_eq!(format!("{}", FkAssumptions::Nf4Sym), "Nf4Sym");
438 assert_eq!(format!("{}", FkAssumptions::Nf3Ind), "Nf3Ind");
439 assert_eq!(format!("{}", FkAssumptions::Nf3Sym), "Nf3Sym");
440 }
441}