@@ -6,6 +6,7 @@ use super::error::{Error, Result};
66use super :: evolution:: { self , AlphasTable , EvolveInfo , OperatorSliceInfo } ;
77use super :: fk_table:: FkTable ;
88use super :: interpolation:: Interp ;
9+ use super :: packed_array:: PackedArray ;
910use super :: pids:: PidBasis ;
1011use super :: reference:: Reference ;
1112use 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) ]
0 commit comments