MARLEY (Model of Argon Reaction Low Energy Yields) v2.0.0
A Monte Carlo event generator for tens-of-MeV neutrino interactions
Loading...
Searching...
No Matches
InterpolationGrid.hh
1
4//
5// This file is part of MARLEY (Model of Argon Reaction Low Energy Yields)
6//
7// MARLEY is free software: you can redistribute it and/or modify it under the
8// terms of version 3 of the GNU General Public License as published by the
9// Free Software Foundation.
10//
11// For the full text of the license please see COPYING or
12// visit http://opensource.org/licenses/GPL-3.0
13//
14// Please respect the MCnet academic usage guidelines. See GUIDELINES
15// or visit https://www.montecarlonet.org/GUIDELINES for details.
16
17#pragma once
18#include <algorithm>
19#include <cmath>
20#include <functional>
21#include <utility>
22#include <vector>
23
24#include "marley/Error.hh"
25#include "marley/marley_utils.hh"
26
27namespace marley {
28
36 template <typename FirstNumericType, typename SecondNumericType
37 = FirstNumericType> class InterpolationGrid
38 {
39 public:
40
41 using OrderedPair = std::pair<FirstNumericType, SecondNumericType>;
42 using Grid = std::vector<OrderedPair>;
43 using GridConstIterator
44 = typename std::vector<OrderedPair>::const_iterator;
45
63 /// </table>
64 enum class InterpolationMethod { Constant = 1,
65 LinearLinear = 2, LinearLog = 3, LogLinear = 4,
66 LogLog = 5 };
67
96 /// </table>
97 enum class ExtrapolationMethod { Zero, Endpoint,
98 Continue, Throw };
99
100 /// @brief Create an InterpolationGrid without any grid points
101 inline InterpolationGrid( InterpolationMethod interp_method
102 = InterpolationMethod::LinearLinear, ExtrapolationMethod extrap_method
103 = ExtrapolationMethod::Zero ) : interpolation_method_( interp_method ),
104 extrapolation_method_( extrap_method )
105 {
106 }
107
108 /// @brief Create an InterpolationGrid from a vector of ordered pairs
109 inline InterpolationGrid( const Grid& grid,
110 InterpolationMethod interp_method = InterpolationMethod::LinearLinear,
111 ExtrapolationMethod extrap_method = ExtrapolationMethod::Zero )
112 : interpolation_method_( interp_method ),
113 extrapolation_method_( extrap_method ), ordered_pairs_( grid )
114 {
116 }
117
118 /// @brief Create an InterpolationGrid from vectors of x and y values
119 inline InterpolationGrid( const std::vector<FirstNumericType>& xs,
120 const std::vector<SecondNumericType>& ys,
121 InterpolationMethod interp_method = InterpolationMethod::LinearLinear,
122 ExtrapolationMethod extrap_method = ExtrapolationMethod::Zero )
123 : interpolation_method_( interp_method ),
124 extrapolation_method_( extrap_method )
125 {
126 if ( xs.size() != ys.size() ) throw marley::Error(
127 std::string("Vectors of x and y values passed to the constructor")
128 + " of marley::InterpolationGrid have unequal sizes." );
129
130 double old_x = marley_utils::minus_infinity;
131 for ( size_t j = 0; j < xs.size(); ++j ) {
132 double new_x = xs.at( j );
133 if ( new_x <= old_x ) throw marley::Error( "The grid point x-values"
134 " defined for a marley::InterpolationGrid object are not strictly"
135 " increasing" );
136 ordered_pairs_.push_back( OrderedPair( xs.at(j), ys.at(j) ) );
137 }
138 };
139
141 SecondNumericType interpolate( FirstNumericType x ) const;
142
144 void insert( FirstNumericType x, SecondNumericType y );
145
147 inline size_t size() const { return ordered_pairs_.size(); }
148
150 inline void clear() { ordered_pairs_.clear(); }
151
153 inline OrderedPair& at( size_t j ) { return ordered_pairs_.at( j ); }
154
156 /// InterpolationGrid
157 inline std::function< SecondNumericType(FirstNumericType) > get_function()
158 {
159 return [ this ]( FirstNumericType x )
160 -> SecondNumericType { return this->interpolate( x ); };
161 }
162
164 /// which the x value is not less than (i.e. greater than or equal to) x
165 inline GridConstIterator lower_bound( const GridConstIterator& begin,
166 const GridConstIterator& end, FirstNumericType x ) const
167 {
168 return std::lower_bound( begin, end, x,
169 []( const OrderedPair& pair, const FirstNumericType& f )
170 -> bool { return pair.first < f; } );
171 }
172
174 /// which the x value is greater than x
175 inline GridConstIterator upper_bound( const
176 GridConstIterator& begin, const GridConstIterator& end,
177 FirstNumericType x ) const
178 {
179 return std::upper_bound( begin, end, x,
180 []( const FirstNumericType& f, const OrderedPair& pair )
181 -> bool { return f < pair.first; } );
182 }
183
185 inline const OrderedPair& front() const { return ordered_pairs_.front(); }
186
188 inline const OrderedPair& back() const { return ordered_pairs_.back(); }
189
190 /// @brief Get the InterpolationMethod used by this InterpolationGrid
192 { return interpolation_method_; }
193
194 /// @brief Set the InterpolationMethod to use
196 { interpolation_method_ = method; }
197
198 /// @brief Get the ExtrapolationMethod used by this InterpolationGrid
200 { return extrapolation_method_; }
201
202 /// @brief Set the ExtrapolationMethod to use
204 { extrapolation_method_ = method; }
205
206 private:
207
209 InterpolationMethod interpolation_method_;
210
213 ExtrapolationMethod extrapolation_method_;
214
216 Grid ordered_pairs_;
217
222 inline void check_grid() const {
224 if ( ordered_pairs_.size() < 2 ) throw marley::Error( "A class method"
225 " was called for an InterpolationGrid object that contains less"
226 " than two grid points." );
227 }
228
232 inline bool find_bin_limits( FirstNumericType x,
233 GridConstIterator& lower_point, GridConstIterator& upper_point ) const
234 {
235 // Check to make sure that the grid contains at least two ordered pairs
236 check_grid();
237
238 // Find the first point on the grid that is not less than x
239 bool extrapolate = false;
240 GridConstIterator begin = ordered_pairs_.begin();
241 GridConstIterator end = ordered_pairs_.end();
242 GridConstIterator not_less_point = lower_bound( begin, end, x );
243
244 // Check whether the requested grid point is within the grid limits
245 if ( not_less_point == begin ) {
246 lower_point = begin;
247 upper_point = begin + 1;
248 // First element of xs > x
249 if ( begin->first != x ) extrapolate = true;
250 }
251 else if ( not_less_point == end ) {
252 // last element of xs < x (extrapolate on the right)
253 extrapolate = true;
254 lower_point = end - 2;
255 upper_point = end - 1;
256 }
257 else {
258 // x is within the grid limits
259 lower_point = not_less_point - 1;
260 upper_point = not_less_point;
261 }
262
263 return extrapolate;
264 }
265 };
266
267 template <typename FirstNumericType, typename SecondNumericType>
268 SecondNumericType InterpolationGrid<FirstNumericType,
269 SecondNumericType>::interpolate( FirstNumericType x ) const
270 {
271 // Find grid points just below [(x1, y1)] and just above [(x2, y2)]
272 InterpolationGrid::GridConstIterator lower_point, upper_point;
273 // Includes a call to check_grid()
274 bool extrapolate = find_bin_limits( x, lower_point, upper_point );
275
276 // If the requested x value is outside of the grid, use the correct method
277 // for dealing with this situation based on the value of
278 if ( extrapolate ) {
279 if ( extrapolation_method_ == ExtrapolationMethod::Zero )
280 return static_cast< SecondNumericType >( 0. );
281 else if ( extrapolation_method_ == ExtrapolationMethod::Endpoint ) {
282 if ( lower_point->first > x ) return lower_point->second;
283 else return upper_point->second;
284 }
285 else if ( extrapolation_method_ == ExtrapolationMethod::Throw ) {
286 throw marley::Error( "x = " + std::to_string( x )
287 + " lies outside of the current interpolation grid object"
288 " (which extends from x_min = "
289 + std::to_string( ordered_pairs_.front().first )
290 + " and x_max = " + std::to_string( ordered_pairs_.back().first )
291 + ") and extrapolation is disabled." );
292 }
293 }
294
295 // Either the requested point falls within the grid or
296 // extrapolation_method == ExtrapolationMethod::Continue. If the "continue"
297 // method for extrapolation is selected, then we continue to use the same
298 // interpolation technique formula outside of the grid (for
299 // InterpolationMethod::LinearLinear, this is linear-linear extrapolation).
300
301 // If the constant interpolation method is selected, then use the *lower
302 // bound* of each bin as the interpolated value. If we're extrapolating,
303 // on the right, use the upper bound.
304 if ( interpolation_method_ == InterpolationMethod::Constant ) {
305 if ( !extrapolate ) return lower_point->second;
306 else if ( lower_point->first > x ) return lower_point->second;
307 else return upper_point->second;
308 }
309
310 // We'll use an interpolation formula for all other methods, so
311 // get the grid point x and y values for later use.
312 FirstNumericType x1 = lower_point->first;
313 FirstNumericType x2 = upper_point->first;
314 SecondNumericType y1 = lower_point->second;
315 SecondNumericType y2 = upper_point->second;
316
317 bool log_x = false, log_y = false;
318 FirstNumericType x_to_use = x;
319 if ( interpolation_method_ == InterpolationMethod::LinearLog )
320 log_x = true;
321 else if ( interpolation_method_ == InterpolationMethod::LogLinear )
322 log_y = true;
323 else if ( interpolation_method_ == InterpolationMethod::LogLog ) {
324 log_x = true;
325 log_y = true;
326 }
327 if ( log_x ) {
328 x1 = std::log( x1 );
329 x2 = std::log( x2 );
330 x_to_use = std::log( x );
331 }
332 if ( log_y ) {
333 y1 = std::log( y1 );
334 y2 = std::log( y2 );
335 }
336
337 FirstNumericType y_interp = y1 + ( (y2 - y1)/(x2 - x1) )*( x_to_use - x1 );
338 if ( log_y ) y_interp = std::exp( y_interp );
339 return y_interp;
340 }
341
342 template < typename FirstNumericType, typename SecondNumericType >
344 FirstNumericType x, SecondNumericType y )
345 {
346 // Figure out where this grid point should go in the grid. Use
347 // std::upper_bound so that entries with the same x value (discontinuities)
348 // are inserted in the order that they are passed to
349 // InterpolationGrid::insert.
350 GridConstIterator insert_point = upper_bound( ordered_pairs_.begin(),
351 ordered_pairs_.end(), x );
352
353 // Insert the new grid point
354 ordered_pairs_.insert( insert_point, OrderedPair(x, y) );
355 }
356
357}
Base class for all exceptions thrown by MARLEY functions.
Definition Error.hh:26
ExtrapolationMethod
Method to use for computing y(x) when the x value lies beyond the grid boundaries.
void insert(FirstNumericType x, SecondNumericType y)
Add a new ordered pair (x, y) to the grid.
const OrderedPair & back() const
Returns a reference to the last ordered pair.
GridConstIterator lower_bound(const GridConstIterator &begin, const GridConstIterator &end, FirstNumericType x) const
Returns a const_iterator to the first element of the grid for which the x value is not less than (i....
std::function< SecondNumericType(FirstNumericType) > get_function()
Get a std::function object that represents y(x) for this InterpolationGrid.
void clear()
Delete all ordered pairs from the grid.
size_t size() const
Get the number of ordered pairs on the grid.
OrderedPair & at(size_t j)
Get a reference to the jth ordered pair from the grid.
void set_interpolation_method(InterpolationMethod method)
Set the InterpolationMethod to use.
SecondNumericType interpolate(FirstNumericType x) const
Compute y(x) using the current InterpolationMethod.
ExtrapolationMethod extrapolation_method() const
Get the ExtrapolationMethod used by this InterpolationGrid.
InterpolationGrid(InterpolationMethod interp_method=InterpolationMethod::LinearLinear, ExtrapolationMethod extrap_method=ExtrapolationMethod::Zero)
Create an InterpolationGrid without any grid points.
InterpolationMethod interpolation_method() const
Get the InterpolationMethod used by this InterpolationGrid.
InterpolationMethod
Method to use for interpolating between (x,y) grid points.
GridConstIterator upper_bound(const GridConstIterator &begin, const GridConstIterator &end, FirstNumericType x) const
Returns a const_iterator to the first element of the grid for which the x value is greater than x.
void set_extrapolation_method(ExtrapolationMethod method)
Set the ExtrapolationMethod to use.
const OrderedPair & front() const
Returns a reference to the first ordered pair.