PDFxTMDLib  1.0.0
CContinuationExtrapolator.h
Go to the documentation of this file.
1 // This file is based on the LHAPDF code
2 
3 #pragma once
4 
9 #include <cmath>
10 #include <iomanip>
11 #include <sstream>
12 namespace PDFxTMD
13 {
14 
15 template <typename Interpolator>
17  : public IcAdvancedPDFExtrapolator<CContinuationExtrapolator<Interpolator>>
18 {
19  public:
20  void setInterpolator(const Interpolator *interpolator)
21  {
22  m_interpolator = interpolator;
23  }
24  void extrapolate(double x, double q2, std::array<double, DEFAULT_TOTAL_PDFS> &output) const
25  {
26  using namespace std;
27  // The ContinuationExtrapolator provides an implementation
28  // of the extrapolation used in the MSTW standalone code
29  // (and LHAPDFv5 when using MSTW sets), G. Watt, October
30  // 2014.
31  auto *reader = m_interpolator->getReader();
32  const auto& xVals_ = reader->getValues(PhaseSpaceComponent::X);
33  const auto& q2Vals_ = reader->getValues(PhaseSpaceComponent::Q2);
34  const size_t nxknots = xVals_.size(); // total number of x knots (all
35  // subgrids)
36  const size_t nq2knots = q2Vals_.size(); // total number of q2 knots (all
37  // subgrids)
38 
39  const double xMin = xVals_.at(0); // first x knot
40  const double xMin1 = xVals_.at(1); // second x knot
41  const double xMax = xVals_.at(nxknots - 1); // last x knot
42 
43  const double q2Min = q2Vals_.at(0); // first q2 knot
44  const double q2Max1 = q2Vals_.at(nq2knots - 2); // second-last q2 knot
45  const double q2Max = q2Vals_.at(nq2knots - 1); // last q2 knot
46 
47  double fxMin = 0, fxMin1 = 0, fq2Max = 0, fq2Max1 = 0, fq2Min = 0, fq2Min1 = 0, xpdf = 0,
48  anom = 0;
49  for (size_t i = 0; i < DEFAULT_TOTAL_PDFS; i += 1)
50  {
52  if (x < xMin && (q2 >= q2Min && q2 <= q2Max))
53  {
54  // Extrapolation in small x only.
55  fxMin = m_interpolator->interpolate(flavor, xMin, q2); // PDF at (xMin,q2)
56  fxMin1 = m_interpolator->interpolate(flavor, xMin1, q2); // PDF at (xMin1,q2)
57  xpdf = _extrapolateLinear(x, xMin, xMin1, fxMin,
58  fxMin1); // PDF at (x,q2)
59  }
60  else if ((x >= xMin && x <= xMax) && q2 > q2Max)
61  {
62  // Extrapolation in large q2 only.
63  fq2Max = m_interpolator->interpolate(flavor, x, q2Max); // PDF at (x,q2Max)
64  fq2Max1 = m_interpolator->interpolate(flavor, x, q2Max1); // PDF at (x,q2Max1)
65  xpdf = _extrapolateLinear(q2, q2Max, q2Max1, fq2Max,
66  fq2Max1); // PDF at (x,q2)
67  }
68  else if (x < xMin && q2 > q2Max)
69  {
70  // Extrapolation in large q2 AND small x.
71  fq2Max = m_interpolator->interpolate(flavor, xMin, q2Max); // PDF at (xMin,q2Max)
72  fq2Max1 = m_interpolator->interpolate(flavor, xMin, q2Max1); // PDF at (xMin,q2Max1)
73  fxMin = _extrapolateLinear(q2, q2Max, q2Max1, fq2Max,
74  fq2Max1); // PDF at (xMin,q2)
75  fq2Max = m_interpolator->interpolate(flavor, xMin1, q2Max); // PDF at (xMin1,q2Max)
76  fq2Max1 =
77  m_interpolator->interpolate(flavor, xMin1, q2Max1); // PDF at (xMin1,q2Max1)
78  fxMin1 = _extrapolateLinear(q2, q2Max, q2Max1, fq2Max,
79  fq2Max1); // PDF at (xMin1,q2)
80  xpdf = _extrapolateLinear(x, xMin, xMin1, fxMin,
81  fxMin1); // PDF at (x,q2)
82  }
83  else if (q2 < q2Min && x <= xMax)
84  {
85  // Extrapolation in small q2.
86 
87  if (x < xMin)
88  {
89  // Extrapolation also in small x.
90 
91  fxMin = m_interpolator->interpolate(flavor, xMin, q2Min); // PDF at (xMin,q2Min)
92  fxMin1 =
93  m_interpolator->interpolate(flavor, xMin1, q2Min); // PDF at (xMin1,q2Min)
94  fq2Min = _extrapolateLinear(x, xMin, xMin1, fxMin,
95  fxMin1); // PDF at (x,q2Min)
96  fxMin = m_interpolator->interpolate(flavor, xMin,
97  1.01 * q2Min); // PDF at (xMin,1.01*q2Min)
98  fxMin1 = m_interpolator->interpolate(flavor, xMin1,
99  1.01 * q2Min); // PDF at (xMin1,1.01*q2Min)
100  fq2Min1 = _extrapolateLinear(x, xMin, xMin1, fxMin,
101  fxMin1); // PDF at (x,1.01*q2Min)
102  }
103  else
104  {
105  // Usual interpolation in x.
106 
107  fq2Min = m_interpolator->interpolate(flavor, x, q2Min); // PDF at (x,q2Min)
108  fq2Min1 = m_interpolator->interpolate(flavor, x,
109  1.01 * q2Min); // PDF at (x,1.01*q2Min)
110  }
111 
112  // Calculate the anomalous dimension, dlog(f)/dlog(q2),
113  // evaluated at q2Min. Then extrapolate the PDFs to low
114  // q2 < q2Min by interpolating the anomalous dimension
115  // between the value at q2Min and a value of 1 for q2 <<
116  // q2Min. If value of PDF at q2Min is very small, just
117  // set anomalous dimension to 1 to prevent rounding
118  // errors. Impose minimum anomalous dimension of -2.5.
119 
120  if (abs(fq2Min) >= 1e-5)
121  {
122  // anom = dlog(f)/dlog(q2) = q2/f * df/dq2 evaluated
123  // at q2 = q2Min, where derivative df/dq2 = (
124  // f(1.01*q2Min) - f(q2Min) ) / (0.01*q2Min).
125  anom = std::max(-2.5, (fq2Min1 - fq2Min) / fq2Min / 0.01);
126  }
127  else
128  anom = 1.0;
129 
130  // Interpolates between f(q2Min)*(q2/q2Min)^anom for q2
131  // ~ q2Min and f(q2Min)*(q2/q2Min) for q2 << q2Min, i.e.
132  // PDFs vanish as q2 --> 0.
133  xpdf = fq2Min * std::pow(q2 / q2Min, anom * q2 / q2Min + 1.0 - q2 / q2Min);
134  }
135  else if (x > xMax)
136  {
137  std::ostringstream oss;
138  oss << "Error in LHAPDF::ContinuationExtrapolator, x > "
139  "xMax (last x knot): ";
140  oss << std::scientific << x << " > " << xMax;
141  throw std::runtime_error(oss.str());
142  }
143  else
144  throw std::runtime_error("We shouldn't be able to get here!");
145 
146  output[i] = xpdf;
147  }
148  }
149  double extrapolate(PartonFlavor flavor, double x, double q2) const
150  {
151  using namespace std;
152  // The ContinuationExtrapolator provides an implementation
153  // of the extrapolation used in the MSTW standalone code
154  // (and LHAPDFv5 when using MSTW sets), G. Watt, October
155  // 2014.
156  auto *reader = m_interpolator->getReader();
157  const auto& xVals_ = reader->getValues(PhaseSpaceComponent::X);
158  const auto& q2Vals_ = reader->getValues(PhaseSpaceComponent::Q2);
159  const size_t nxknots = xVals_.size(); // total number of x knots (all
160  // subgrids)
161  const size_t nq2knots = q2Vals_.size(); // total number of q2 knots (all
162  // subgrids)
163  const double xMin = xVals_.at(0); // first x knot
164  const double xMin1 = xVals_.at(1); // second x knot
165  const double xMax = xVals_.at(nxknots - 1); // last x knot
166 
167  const double q2Min = q2Vals_.at(0); // first q2 knot
168  const double q2Max1 = q2Vals_.at(nq2knots - 2); // second-last q2 knot
169  const double q2Max = q2Vals_.at(nq2knots - 1); // last q2 knot
170 
171  double fxMin, fxMin1, fq2Max, fq2Max1, fq2Min, fq2Min1, xpdf, anom;
172 
173  if (x < xMin && (q2 >= q2Min && q2 <= q2Max))
174  {
175  // Extrapolation in small x only.
176  fxMin = m_interpolator->interpolate(flavor, xMin, q2); // PDF at (xMin,q2)
177  fxMin1 = m_interpolator->interpolate(flavor, xMin1, q2); // PDF at (xMin1,q2)
178  xpdf = _extrapolateLinear(x, xMin, xMin1, fxMin,
179  fxMin1); // PDF at (x,q2)
180  }
181  else if ((x >= xMin && x <= xMax) && q2 > q2Max)
182  {
183  // Extrapolation in large q2 only.
184  fq2Max = m_interpolator->interpolate(flavor, x, q2Max); // PDF at (x,q2Max)
185  fq2Max1 = m_interpolator->interpolate(flavor, x, q2Max1); // PDF at (x,q2Max1)
186  xpdf = _extrapolateLinear(q2, q2Max, q2Max1, fq2Max,
187  fq2Max1); // PDF at (x,q2)
188  }
189  else if (x < xMin && q2 > q2Max)
190  {
191  // Extrapolation in large q2 AND small x.
192  fq2Max = m_interpolator->interpolate(flavor, xMin, q2Max); // PDF at (xMin,q2Max)
193  fq2Max1 = m_interpolator->interpolate(flavor, xMin, q2Max1); // PDF at (xMin,q2Max1)
194  fxMin = _extrapolateLinear(q2, q2Max, q2Max1, fq2Max,
195  fq2Max1); // PDF at (xMin,q2)
196  fq2Max = m_interpolator->interpolate(flavor, xMin1, q2Max); // PDF at (xMin1,q2Max)
197  fq2Max1 = m_interpolator->interpolate(flavor, xMin1, q2Max1); // PDF at (xMin1,q2Max1)
198  fxMin1 = _extrapolateLinear(q2, q2Max, q2Max1, fq2Max,
199  fq2Max1); // PDF at (xMin1,q2)
200  xpdf = _extrapolateLinear(x, xMin, xMin1, fxMin,
201  fxMin1); // PDF at (x,q2)
202  }
203  else if (q2 < q2Min && x <= xMax)
204  {
205  // Extrapolation in small q2.
206 
207  if (x < xMin)
208  {
209  // Extrapolation also in small x.
210 
211  fxMin = m_interpolator->interpolate(flavor, xMin, q2Min); // PDF at (xMin,q2Min)
212  fxMin1 = m_interpolator->interpolate(flavor, xMin1, q2Min); // PDF at (xMin1,q2Min)
213  fq2Min = _extrapolateLinear(x, xMin, xMin1, fxMin,
214  fxMin1); // PDF at (x,q2Min)
215  fxMin = m_interpolator->interpolate(flavor, xMin,
216  1.01 * q2Min); // PDF at (xMin,1.01*q2Min)
217  fxMin1 = m_interpolator->interpolate(flavor, xMin1,
218  1.01 * q2Min); // PDF at (xMin1,1.01*q2Min)
219  fq2Min1 = _extrapolateLinear(x, xMin, xMin1, fxMin,
220  fxMin1); // PDF at (x,1.01*q2Min)
221  }
222  else
223  {
224  // Usual interpolation in x.
225 
226  fq2Min = m_interpolator->interpolate(flavor, x, q2Min); // PDF at (x,q2Min)
227  fq2Min1 = m_interpolator->interpolate(flavor, x,
228  1.01 * q2Min); // PDF at (x,1.01*q2Min)
229  }
230 
231  // Calculate the anomalous dimension, dlog(f)/dlog(q2),
232  // evaluated at q2Min. Then extrapolate the PDFs to low
233  // q2 < q2Min by interpolating the anomalous dimension
234  // between the value at q2Min and a value of 1 for q2 <<
235  // q2Min. If value of PDF at q2Min is very small, just
236  // set anomalous dimension to 1 to prevent rounding
237  // errors. Impose minimum anomalous dimension of -2.5.
238 
239  if (abs(fq2Min) >= 1e-5)
240  {
241  // anom = dlog(f)/dlog(q2) = q2/f * df/dq2 evaluated
242  // at q2 = q2Min, where derivative df/dq2 = (
243  // f(1.01*q2Min) - f(q2Min) ) / (0.01*q2Min).
244  anom = std::max(-2.5, (fq2Min1 - fq2Min) / fq2Min / 0.01);
245  }
246  else
247  anom = 1.0;
248 
249  // Interpolates between f(q2Min)*(q2/q2Min)^anom for q2
250  // ~ q2Min and f(q2Min)*(q2/q2Min) for q2 << q2Min, i.e.
251  // PDFs vanish as q2 --> 0.
252  xpdf = fq2Min * std::pow(q2 / q2Min, anom * q2 / q2Min + 1.0 - q2 / q2Min);
253  }
254  else if (x > xMax)
255  {
256  std::ostringstream oss;
257  oss << "Error in LHAPDF::ContinuationExtrapolator, x > "
258  "xMax (last x knot): ";
259  oss << std::scientific << x << " > " << xMax;
260  throw std::runtime_error(oss.str());
261  }
262  else
263  throw std::runtime_error("We shouldn't be able to get here!");
264 
265  return xpdf;
266  }
267 
268  private:
269  const Interpolator *m_interpolator = nullptr;
270 };
271 } // namespace PDFxTMD
#define DEFAULT_TOTAL_PDFS
Definition: PartonUtils.h:17
Definition: CContinuationExtrapolator.h:18
double extrapolate(PartonFlavor flavor, double x, double q2) const
Definition: CContinuationExtrapolator.h:149
void setInterpolator(const Interpolator *interpolator)
Definition: CContinuationExtrapolator.h:20
void extrapolate(double x, double q2, std::array< double, DEFAULT_TOTAL_PDFS > &output) const
Definition: CContinuationExtrapolator.h:24
Definition: IExtrapolator.h:39
Definition: AllFlavorsShape.h:14
PartonFlavor
Definition: PartonUtils.h:58
double _extrapolateLinear(double x, double xl, double xh, double yl, double yh)
constexpr std::array< PartonFlavor, DEFAULT_TOTAL_PDFS > standardPartonFlavors
Definition: PartonUtils.h:80