Skip to content

Commit cf562d2

Browse files
Implement a fix_convolution method for Grids
1 parent 388b6c8 commit cf562d2

File tree

2 files changed

+222
-16
lines changed

2 files changed

+222
-16
lines changed

pineappl/src/grid.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use super::error::{Error, Result};
66
use super::evolution::{self, AlphasTable, EvolveInfo, OperatorSliceInfo};
77
use super::fk_table::FkTable;
88
use super::interpolation::Interp;
9+
use super::packed_array::PackedArray;
910
use super::pids::PidBasis;
1011
use super::reference::Reference;
1112
use super::subgrid::{
@@ -1437,6 +1438,181 @@ impl Grid {
14371438

14381439
self.channels = new_channels;
14391440
}
1441+
1442+
/// Fix one of the convolutions in the Grid and return a new Grid with lower dimension.
1443+
///
1444+
/// # Panics
1445+
///
1446+
/// TODO
1447+
///
1448+
/// # Errors
1449+
///
1450+
/// Returns an error if the Grid has only one single convolution.
1451+
pub fn fix_convolution(
1452+
&self,
1453+
conv_idx: usize,
1454+
xfx: &mut dyn FnMut(i32, f64, f64) -> f64,
1455+
alphas: &mut dyn FnMut(f64) -> f64,
1456+
xi: (f64, f64, f64),
1457+
) -> Result<Self> {
1458+
if self.convolutions.len() <= 1 {
1459+
return Err(Error::General(
1460+
"cannot fix the last convolution".to_string(),
1461+
));
1462+
}
1463+
1464+
if conv_idx >= self.convolutions.len() {
1465+
return Err(Error::General(format!(
1466+
"convolution index {} out of bounds (max: {})",
1467+
conv_idx,
1468+
self.convolutions.len() - 1
1469+
)));
1470+
}
1471+
1472+
let mut new_convolutions = self.convolutions.clone();
1473+
new_convolutions.remove(conv_idx);
1474+
1475+
let mut new_kinematics = self.kinematics.clone();
1476+
let mut new_interps = self.interps.clone();
1477+
let kin_pos = new_kinematics
1478+
.iter()
1479+
.position(|k| *k == Kinematics::X(conv_idx))
1480+
.unwrap();
1481+
new_kinematics.remove(kin_pos);
1482+
new_interps.remove(kin_pos);
1483+
1484+
for kin in &mut new_kinematics {
1485+
if let Kinematics::X(i) = kin {
1486+
if *i > conv_idx {
1487+
*i -= 1;
1488+
}
1489+
}
1490+
}
1491+
1492+
let mut new_channel_map: BTreeMap<Vec<i32>, Vec<(usize, i32, f64)>> = BTreeMap::new();
1493+
for (ichan, chan) in self.channels().iter().enumerate() {
1494+
for (pids, factor) in chan.entry() {
1495+
let mut new_pids = pids.clone();
1496+
let fixed_pid = new_pids.remove(conv_idx);
1497+
1498+
new_channel_map
1499+
.entry(new_pids)
1500+
.or_default()
1501+
.push((ichan, fixed_pid, *factor));
1502+
}
1503+
}
1504+
1505+
let new_channels: Vec<Channel> = new_channel_map
1506+
.keys()
1507+
.map(|pids| Channel::new(vec![(pids.clone(), 1.0)]))
1508+
.collect();
1509+
let new_channel_pids: Vec<_> = new_channel_map.keys().cloned().collect();
1510+
1511+
let mut new_subgrids = Array3::from_shape_simple_fn(
1512+
(self.orders.len(), self.bwfl.len(), new_channels.len()),
1513+
|| EmptySubgridV1.into(),
1514+
);
1515+
1516+
let conv_to_fix = &self.convolutions[conv_idx];
1517+
let (xir, xif, xia) = xi;
1518+
1519+
for (inew_chan, new_pids) in new_channel_pids.iter().enumerate() {
1520+
let origins = &new_channel_map[new_pids];
1521+
1522+
for (iord, order) in self.orders().iter().enumerate() {
1523+
for (ibin, _) in self.bwfl().bins().iter().enumerate() {
1524+
let mut intermediate_sg: Option<SubgridEnum> = None;
1525+
1526+
for &(ichan_orig, pid_fixed, factor) in origins {
1527+
let sg_orig = &self.subgrids[[iord, ibin, ichan_orig]];
1528+
if sg_orig.is_empty() {
1529+
continue;
1530+
}
1531+
1532+
let mut new_node_values = sg_orig.node_values();
1533+
new_node_values.remove(kin_pos);
1534+
1535+
let mut sg_new_array = PackedArray::new(
1536+
new_node_values.iter().map(std::vec::Vec::len).collect(),
1537+
);
1538+
1539+
let scale_form = if conv_to_fix.conv_type().is_pdf() {
1540+
&self.scales.fac
1541+
} else {
1542+
&self.scales.frg
1543+
};
1544+
let xi_factor = if conv_to_fix.conv_type().is_pdf() {
1545+
xif
1546+
} else {
1547+
xia
1548+
};
1549+
1550+
for (mut idxs_orig, val_orig) in sg_orig.indexed_iter() {
1551+
let x_val = idxs_orig.remove(kin_pos);
1552+
1553+
let sg_orig_node_values = sg_orig.node_values();
1554+
let self_kinematics = self.kinematics();
1555+
1556+
let scale_dims: Vec<_> = sg_orig_node_values
1557+
.iter()
1558+
.enumerate()
1559+
.filter(|(i, _)| {
1560+
matches!(self_kinematics.get(*i), Some(Kinematics::Scale(_)))
1561+
})
1562+
.map(|(_, v)| v.len())
1563+
.collect();
1564+
let mu2_nodes_calc =
1565+
scale_form.calc(&sg_orig_node_values, self_kinematics);
1566+
let mu2_idx = scale_form.idx(&idxs_orig, &scale_dims);
1567+
let mu2_val = mu2_nodes_calc[mu2_idx] * xi_factor * xi_factor;
1568+
1569+
let ren_mu2_nodes_calc =
1570+
self.scales.ren.calc(&sg_orig_node_values, self_kinematics);
1571+
let ren_mu2 = ren_mu2_nodes_calc
1572+
[self.scales.ren.idx(&idxs_orig, &scale_dims)]
1573+
* xir
1574+
* xir;
1575+
let alphas_val = alphas(ren_mu2).powi(order.alphas.into());
1576+
1577+
let x = sg_orig_node_values[kin_pos][x_val];
1578+
let pdf_val = xfx(pid_fixed, x, mu2_val) / x;
1579+
let final_val = val_orig * factor * pdf_val * alphas_val;
1580+
1581+
sg_new_array[idxs_orig.as_slice()] += final_val;
1582+
}
1583+
1584+
let sg_contrib: SubgridEnum =
1585+
ImportSubgridV1::new(sg_new_array, new_node_values).into();
1586+
1587+
if let Some(ref mut isg) = intermediate_sg {
1588+
isg.merge(&sg_contrib, None);
1589+
} else {
1590+
intermediate_sg = Some(sg_contrib);
1591+
}
1592+
}
1593+
1594+
if let Some(sg) = intermediate_sg {
1595+
new_subgrids[[iord, ibin, inew_chan]] = sg;
1596+
}
1597+
}
1598+
}
1599+
}
1600+
1601+
let mut new_grid = Self::new(
1602+
self.bwfl.clone(),
1603+
self.orders.clone(),
1604+
new_channels,
1605+
*self.pid_basis(),
1606+
new_convolutions,
1607+
new_interps,
1608+
new_kinematics,
1609+
self.scales.clone(),
1610+
);
1611+
new_grid.subgrids = new_subgrids;
1612+
new_grid.metadata = self.metadata.clone();
1613+
1614+
Ok(new_grid)
1615+
}
14401616
}
14411617

14421618
#[cfg(test)]

pineappl/tests/drell_yan_lo.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -366,26 +366,56 @@ fn perform_grid_tests(
366366
assert_approx_eq!(f64, *result, *reference, ulps = 8);
367367
}
368368

369-
// TEST 5b: `convolve` with `ConvolutionCache::with_two`
370-
let mut xfx1 = |id, x, q2| pdf.xfx_q2(id, x, q2);
371-
let mut xfx2 = |id, x, q2| pdf.xfx_q2(id, x, q2);
372-
let mut alphas2 = |_| 0.0;
373-
let mut convolution_cache2 = ConvolutionCache::new(
374-
vec![
375-
Conv::new(ConvType::UnpolPDF, 2212),
376-
Conv::new(ConvType::UnpolPDF, 2212),
377-
],
378-
vec![&mut xfx1, &mut xfx2],
379-
&mut alphas2,
369+
// TEST 6a: Fix conv_idx = 0 (first hadron)
370+
let mut xfx_fixed_0 = |id, x, q2| pdf.xfx_q2(id, x, q2);
371+
let mut alphas_for_fix_0 = |_| 0.0;
372+
let grid_fixed_0 =
373+
grid.fix_convolution(0, &mut xfx_fixed_0, &mut alphas_for_fix_0, (1.0, 1.0, 1.0))?;
374+
375+
let mut xfx_convolve_0 = |id, x, q2| pdf.xfx_q2(id, x, q2);
376+
let mut alphas_convolve_0 = |_| 0.0;
377+
let mut convolution_cache_one_0 = ConvolutionCache::new(
378+
vec![Conv::new(ConvType::UnpolPDF, 2212)],
379+
vec![&mut xfx_convolve_0],
380+
&mut alphas_convolve_0,
381+
);
382+
let bins_fixed_0 = grid_fixed_0.convolve(
383+
&mut convolution_cache_one_0,
384+
&[],
385+
&[],
386+
&[],
387+
&[(1.0, 1.0, 1.0)],
380388
);
381-
let bins2 = grid.convolve(&mut convolution_cache2, &[], &[], &[], &[(1.0, 1.0, 1.0)]);
382389

383-
for (result, reference) in bins2.iter().zip(reference.iter()) {
384-
assert_approx_eq!(f64, *result, *reference, ulps = 16);
390+
for (result, original_val) in bins_fixed_0.iter().zip(bins.iter()) {
391+
assert_approx_eq!(f64, *result, *original_val, ulps = 16);
385392
}
393+
mem::drop(convolution_cache_one_0);
394+
395+
// TEST 6b: Fix conv_idx = 1 (second hadron)
396+
let mut xfx_fixed_1 = |id, x, q2| pdf.xfx_q2(id, x, q2);
397+
let mut alphas_for_fix_1 = |_| 0.0;
398+
let grid_fixed_1 =
399+
grid.fix_convolution(1, &mut xfx_fixed_1, &mut alphas_for_fix_1, (1.0, 1.0, 1.0))?;
400+
401+
let mut xfx_convolve_1 = |id, x, q2| pdf.xfx_q2(id, x, q2);
402+
let mut alphas_convolve_1 = |_| 0.0;
403+
let mut convolution_cache_one_1 = ConvolutionCache::new(
404+
vec![Conv::new(ConvType::UnpolPDF, 2212)],
405+
vec![&mut xfx_convolve_1],
406+
&mut alphas_convolve_1,
407+
);
408+
let bins_fixed_1 = grid_fixed_1.convolve(
409+
&mut convolution_cache_one_1,
410+
&[],
411+
&[],
412+
&[],
413+
&[(1.0, 1.0, 1.0)],
414+
);
386415

387-
mem::drop(convolution_cache2);
388-
mem::drop(bins2);
416+
for (result, original_val) in bins_fixed_1.iter().zip(bins.iter()) {
417+
assert_approx_eq!(f64, *result, *original_val, ulps = 16);
418+
}
389419

390420
// TEST 7a: `optimize_using` - tests `symmetrize` for each subgrid type
391421
grid.optimize_using(GridOptFlags::SYMMETRIZE_CHANNELS);

0 commit comments

Comments
 (0)