#pragma once #include "StarMultiArrayInterpolator.hpp" namespace Star { // Provides a method for storing, retrieving, and interpolating uneven // n-variate data. Access times involve a binary search over the domain of // each dimension, so is O(log(n)*m) where n is the size of the largest // dimension, and m is the table_rank. template class MultiTable { public: typedef ElementT Element; typedef PositionT Position; static size_t const Rank = RankN; typedef Star::MultiArray MultiArray; typedef Star::MultiArrayInterpolator2 Interpolator2; typedef Star::MultiArrayInterpolator4 Interpolator4; typedef Star::MultiArrayPiecewiseInterpolator PiecewiseInterpolator; typedef Array PositionArray; typedef Array WeightArray2; typedef Array WeightArray4; typedef typename MultiArray::SizeArray SizeArray; typedef typename MultiArray::IndexArray IndexArray; typedef List Range; typedef Array RangeArray; typedef std::function WeightFunction2; typedef std::function WeightFunction4; typedef std::function InterpolateFunction; MultiTable() : m_interpolationMode(InterpolationMode::Linear), m_boundMode(BoundMode::Clamp) {} // Set input ranges on a particular dimension. Will resize underlying storage // to fit range. void setRange(std::size_t dim, Range const& range) { SizeArray sizes = m_array.size(); sizes[dim] = range.size(); m_array.resize(sizes); m_ranges[dim] = range; } void setRanges(RangeArray const& ranges) { SizeArray arraySize; for (size_t dim = 0; dim < Rank; ++dim) { arraySize[dim] = ranges[dim].size(); m_ranges[dim] = ranges[dim]; } m_array.resize(arraySize); } // Set array element based on index. void set(IndexArray const& index, Element const& element) { m_array.set(index, element); } // Get array element based on index. Element const& get(IndexArray const& index) const { return m_array(index); } MultiArray const& array() const { return m_array; } MultiArray& array() { return m_array; } InterpolationMode interpolationMode() const { return m_interpolationMode; } void setInterpolationMode(InterpolationMode interpolationMode) { m_interpolationMode = interpolationMode; } BoundMode boundMode() const { return m_boundMode; } void setBoundMode(BoundMode boundMode) { m_boundMode = boundMode; } Element interpolate(PositionArray const& coord) const { if (m_interpolationMode == InterpolationMode::HalfStep) { PiecewiseInterpolator piecewiseInterpolator(StepWeightOperator(), m_boundMode); return piecewiseInterpolator.interpolate(m_array, toIndexSpace(coord)); } else if (m_interpolationMode == InterpolationMode::Linear) { Interpolator2 interpolator2(LinearWeightOperator(), m_boundMode); return interpolator2.interpolate(m_array, toIndexSpace(coord)); } else if (m_interpolationMode == InterpolationMode::Cubic) { // MultiTable uses CubicWeights with linear extrapolation (not // configurable atm) Interpolator4 interpolator4(Cubic4WeightOperator(true), m_boundMode); return interpolator4.interpolate(m_array, toIndexSpace(coord)); } else { throw MathException("Unsupported interpolation type in MultiTable::interpolate"); } } // Synonym for inteprolate Element operator()(PositionArray const& coord) const { return interpolate(coord); } // op should take a PositionArray parameter and return an element. template void eval(OpType op) { m_array.forEach(EvalWrapper(op, *this)); } private: template inline PositionArray toIndexSpace(Coordinate const& coord) const { PositionArray indexCoord; for (size_t i = 0; i < Rank; ++i) indexCoord[i] = inverseLinearInterpolateLower(m_ranges[i].begin(), m_ranges[i].end(), coord[i]); return indexCoord; } template struct EvalWrapper { EvalWrapper(OpType& o, MultiTable const& t) : op(o), table(t) {} template void operator()(IndexArray const& indexArray, Element& element) { PositionArray rangeArray; for (size_t i = 0; i < Rank; ++i) rangeArray[i] = table.m_ranges[i][indexArray[i]]; element = op(rangeArray); } OpType& op; MultiTable const& table; }; RangeArray m_ranges; MultiArray m_array; InterpolationMode m_interpolationMode; BoundMode m_boundMode; }; typedef MultiTable MultiTable2F; typedef MultiTable MultiTable2D; typedef MultiTable MultiTable3F; typedef MultiTable MultiTable3D; typedef MultiTable MultiTable4F; typedef MultiTable MultiTable4D; }