31#ifndef __TASMANIAN_SPARSE_GRID_LPOLY_HPP
32#define __TASMANIAN_SPARSE_GRID_LPOLY_HPP
34#include "tsgGridCore.hpp"
38#ifndef __TASMANIAN_DOXYGEN_SKIP
39class GridLocalPolynomial final :
public BaseCanonicalGrid{
41 GridLocalPolynomial(AccelerationContext
const *acc) : BaseCanonicalGrid(acc), order(1), top_level(0){}
42 friend struct GridReaderVersion5<GridLocalPolynomial>;
43 GridLocalPolynomial(AccelerationContext
const *acc,
const GridLocalPolynomial *pwpoly,
int ibegin,
int iend);
44 GridLocalPolynomial(AccelerationContext
const *acc,
int cnum_dimensions,
int cnum_outputs,
int depth,
int corder, TypeOneDRule crule,
const std::vector<int> &level_limits);
45 ~GridLocalPolynomial() =
default;
47 GridLocalPolynomial(GridLocalPolynomial &&) =
default;
48 GridLocalPolynomial &operator = (GridLocalPolynomial &&) =
default;
50 bool isLocalPolynomial()
const override{
return true; }
52 void write(std::ostream &os,
bool iomode)
const override{
if (iomode == mode_ascii) write<mode_ascii>(os);
else write<mode_binary>(os); }
54 template<
bool iomode>
void write(std::ostream &os)
const;
56 TypeOneDRule getRule()
const override{
return RuleLocal::getRule(effective_rule); }
57 int getOrder()
const{
return order; }
59 template<RuleLocal::erule,
typename po
ints_mode>
60 void getPoints(
double *x)
const;
61 void getLoadedPoints(
double *x)
const override;
62 void getNeededPoints(
double *x)
const override;
63 void getPoints(
double *x)
const override;
65 template<RuleLocal::erule effrule>
66 void getQuadratureWeights(
double weights[])
const;
67 void getQuadratureWeights(
double weights[])
const override;
68 void getInterpolationWeights(
const double x[],
double weights[])
const override;
69 void getDifferentiationWeights(
const double x[],
double weights[])
const override;
73 void evaluate(
const double x[],
double y[])
const override;
74 void integrate(
double q[],
double *conformal_correction)
const override;
75 void differentiate(
const double x[],
double jacobian[])
const override;
77 void evaluateBatchOpenMP(
const double x[],
int num_x,
double y[])
const;
78 void evaluateBatch(
const double x[],
int num_x,
double y[])
const override;
80 void loadNeededValuesGPU(
const double *vals);
81 void evaluateGpuMixed(
const double x[],
int num_x,
double y[])
const;
82 void evaluateBatchGPU(
const double gpu_x[],
int cpu_num_x,
double gpu_y[])
const override;
83 void evaluateBatchGPU(
const float gpu_x[],
int cpu_num_x,
float gpu_y[])
const override;
84 template<
typename T>
void evaluateBatchGPUtempl(
const T gpu_x[],
int cpu_num_x, T gpu_y[])
const;
85 void evaluateHierarchicalFunctionsGPU(
const double gpu_x[],
int cpu_num_x,
double *gpu_y)
const override;
86 void buildSparseBasisMatrixGPU(
const double gpu_x[],
int cpu_num_x, GpuVector<int> &gpu_spntr, GpuVector<int> &gpu_sindx, GpuVector<double> &gpu_svals)
const;
87 void evaluateHierarchicalFunctionsGPU(
const float gpu_x[],
int cpu_num_x,
float *gpu_y)
const override;
88 void buildSparseBasisMatrixGPU(
const float gpu_x[],
int cpu_num_x, GpuVector<int> &gpu_spntr, GpuVector<int> &gpu_sindx, GpuVector<float> &gpu_svals)
const;
90 void setSurplusRefinement(
double tolerance, TypeRefinement criteria,
int output,
const std::vector<int> &level_limits,
const double *scale_correction);
91 void clearRefinement()
override;
92 void mergeRefinement()
override;
99 std::vector<double> getScaledCoefficients(
int output,
const double *scale_correction);
100 int removePointsByHierarchicalCoefficient(
double tolerance,
int output,
const double *scale_correction);
101 void removePointsByHierarchicalCoefficient(
int new_num_points,
int output,
const double *scale_correction);
107 int removeMappedPoints(std::vector<bool>
const &pmap);
109 void beginConstruction()
override;
110 void writeConstructionData(std::ostream &os,
bool)
const override;
111 void readConstructionData(std::istream &is,
bool)
override;
112 template<RuleLocal::erule effrule>
113 std::vector<double> getCandidateConstructionPoints(
double tolerance, TypeRefinement criteria,
int output, std::vector<int>
const &level_limits,
double const *scale_correction);
114 std::vector<double> getCandidateConstructionPoints(
double tolerance, TypeRefinement criteria,
int output, std::vector<int>
const &level_limits,
double const *scale_correction);
115 template<RuleLocal::erule effrule>
116 void loadConstructedPoint(
const double x[],
const std::vector<double> &y);
117 void loadConstructedPoint(
const double x[],
const std::vector<double> &y)
override;
118 template<RuleLocal::erule effrule>
119 void loadConstructedPoint(
const double x[],
int numx,
const double y[]);
120 void loadConstructedPoint(
const double x[],
int numx,
const double y[])
override;
121 void finishConstruction()
override;
123 void evaluateHierarchicalFunctions(
const double x[],
int num_x,
double y[])
const override;
124 std::vector<double> getSupport() const override final;
125 void setHierarchicalCoefficients(const
double c[]) override;
126 void integrateHierarchicalFunctions(
double integrals[]) const override;
128 void updateAccelerationData(AccelerationContext::ChangeType change) const override;
130 const
double* getSurpluses() const;
131 const
int* getNeededIndexes() const;
133 void buildSpareBasisMatrix(const
double x[],
int num_x,
int num_chunk, std::vector<
int> &spntr, std::vector<
int> &sindx, std::vector<
double> &svals) const;
134 void buildSpareBasisMatrixStatic(const
double x[],
int num_x,
int num_chunk,
int *spntr,
int *sindx,
double *svals) const;
135 int getSpareBasisMatrixNZ(const
double x[],
int num_x) const;
139 GridLocalPolynomial(AccelerationContext const *acc,
int cnum_dimensions,
int cnum_outputs,
int corder, TypeOneDRule crule, std::vector<
int> &&pnts, std::vector<
double> &&vals, std::vector<
double> &&surps);
142 void updateValues(
double const *vals);
147 template<RuleLocal::erule effrule>
148 std::vector<
int> getSubGraph(std::vector<
int> const &point) const;
151 template<RuleLocal::erule effrule>
152 void expandGrid(std::vector<
int> const &point, std::vector<
double> const &value);
155 template<RuleLocal::erule effrule>
156 std::vector<
int> getMultiIndex(const
double x[]);
159 template<RuleLocal::erule effrule>
160 void loadConstructedPoints();
163 template<RuleLocal::erule effrule>
164 void recomputeSurpluses();
166 void recomputeSurpluses();
183 template<RuleLocal::erule effrule>
184 void updateSurpluses(MultiIndexSet const &work,
int max_level, std::vector<
int> const &level, Data2D<
int> const &dagUp);
190 enum class TranspMode {
197 template<TranspMode mode>
198 void applyTransformationTransposed(
double weights[],
const MultiIndexSet &work,
const std::vector<int> &active_points)
const;
199 template<TranspMode mode, RuleLocal::erule effrule>
200 void applyTransformationTransposed(
double weights[],
const MultiIndexSet &work,
const std::vector<int> &active_points)
const;
202 void buildSparseMatrixBlockForm(
const double x[],
int num_x,
int num_chunk, std::vector<int> &numnz,
203 std::vector<std::vector<int>> &tindx, std::vector<std::vector<double>> &tvals)
const;
205 template<RuleLocal::erule eff_rule>
206 double evalBasisSupported(
const int point[],
const double x[],
bool &isSupported)
const{
207 double f = RuleLocal::evalSupport<eff_rule>(order, point[0], x[0], isSupported);
208 if (!isSupported)
return 0.0;
209 for(
int j=1; j<num_dimensions; j++){
210 f *= RuleLocal::evalSupport<eff_rule>(order, point[j], x[j], isSupported);
211 if (!isSupported)
return 0.0;
215 template<RuleLocal::erule effrule>
216 void diffBasisSupported(
const int point[],
const double x[],
double diff_values[],
bool &isSupported)
const{
220 std::fill_n(diff_values, num_dimensions, 1);
221 for(
int k=0; k<num_dimensions; k++) {
222 bool constexpr use_edge_support =
true;
223 double fval = RuleLocal::evalSupport<effrule, use_edge_support>(order, point[k], x[k], isSupported);
224 if (not isSupported) {
225 std::fill_n(diff_values, num_dimensions, 0);
231 for(
int j=0; j<k; j++) diff_values[j] *= fval;
232 for(
int j=k+1; j<num_dimensions; j++) diff_values[j] *= fval;
234 for (
int k=0; k<num_dimensions; k++) {
235 diff_values[k] *= RuleLocal::diffSupport<effrule>(order, point[k], x[k]);
246 enum class WalkerMode {
269 template<WalkerMode mode, RuleLocal::erule effrule>
270 void walkTree(
const MultiIndexSet &work,
const double x[], std::vector<int> &sindx, std::vector<double> &svals,
double *y)
const{
271 std::vector<int> monkey_count(top_level+1);
272 std::vector<int> monkey_tail(top_level+1);
276 std::vector<double> basis_derivative(num_dimensions);
278 for(
const auto &r : roots){
279 if constexpr (mode == WalkerMode::increment_diff or mode == WalkerMode::fill_entries_diff) {
280 diffBasisSupported<effrule>(work.getIndex(r), x, basis_derivative.data(), isSupported);
282 basis_value = evalBasisSupported<effrule>(work.getIndex(r), x, isSupported);
286 if constexpr (mode == WalkerMode::increment){
287 double const *s = surpluses.getStrip(r);
288 for(
int k=0; k<num_outputs; k++)
289 y[k] += basis_value * s[k];
290 }
else if constexpr (mode == WalkerMode::fill_entries or mode == WalkerMode::fill_sorted){
292 svals.push_back(basis_value);
293 }
else if constexpr (mode == WalkerMode::increment_diff){
294 double const *s = surpluses.getStrip(r);
295 for(
int k=0; k<num_outputs; k++)
296 for (
int d=0; d<num_dimensions; d++)
297 y[k * num_dimensions + d] += basis_derivative[d] * s[k];
300 for (
auto dx : basis_derivative)
306 monkey_count[0] = pntr[r];
308 while(monkey_count[0] < pntr[monkey_tail[0]+1]){
309 if (monkey_count[current] < pntr[monkey_tail[current]+1]){
310 int p = indx[monkey_count[current]];
311 if constexpr (mode == WalkerMode::increment_diff or mode == WalkerMode::fill_entries_diff){
312 diffBasisSupported<effrule>(work.getIndex(p), x, basis_derivative.data(), isSupported);
314 basis_value = evalBasisSupported<effrule>(work.getIndex(p), x, isSupported);
317 if constexpr (mode == WalkerMode::increment){
318 double const *s = surpluses.getStrip(p);
319 for(
int k=0; k<num_outputs; k++)
320 y[k] += basis_value * s[k];
321 }
else if constexpr (mode == WalkerMode::fill_entries or mode == WalkerMode::fill_sorted){
323 svals.push_back(basis_value);
324 }
else if constexpr (mode == WalkerMode::increment_diff){
325 double const *s = surpluses.getStrip(p);
326 for(
int k=0; k<num_outputs; k++)
327 for (
int d=0; d<num_dimensions; d++)
328 y[k * num_dimensions + d] += basis_derivative[d] * s[k];
331 for (
auto dx : basis_derivative)
334 monkey_tail[++current] = p;
335 monkey_count[current] = pntr[p];
337 monkey_count[current]++;
340 monkey_count[--current]++;
350 if constexpr (mode == WalkerMode::fill_sorted){
351 std::vector<int> map(sindx);
352 std::iota(map.begin(), map.end(), 0);
353 std::sort(map.begin(), map.end(), [&](
int a,
int b)->bool{ return (sindx[a] < sindx[b]); });
355 std::vector<int> idx = sindx;
356 std::vector<double> vls = svals;
357 std::transform(map.begin(), map.end(), sindx.begin(), [&](
int i)->int{ return idx[i]; });
358 std::transform(map.begin(), map.end(), svals.begin(), [&](
int i)->double{ return vls[i]; });
362 template<WalkerMode mode>
363 void walkTree(
const MultiIndexSet &work,
const double x[], std::vector<int> &sindx, std::vector<double> &svals,
double *y)
const{
364 switch(effective_rule) {
365 case RuleLocal::erule::pwc:
366 walkTree<mode, RuleLocal::erule::pwc>(work,x, sindx, svals, y);
368 case RuleLocal::erule::localp:
369 walkTree<mode, RuleLocal::erule::localp>(work,x, sindx, svals, y);
371 case RuleLocal::erule::semilocalp:
372 walkTree<mode, RuleLocal::erule::semilocalp>(work,x, sindx, svals, y);
374 case RuleLocal::erule::localp0:
375 walkTree<mode, RuleLocal::erule::localp0>(work,x, sindx, svals, y);
378 walkTree<mode, RuleLocal::erule::localpb>(work,x, sindx, svals, y);
383 template<RuleLocal::erule effrule>
384 double evalBasisRaw(
const int point[],
const double x[])
const {
385 double f = RuleLocal::evalRaw<effrule>(order, point[0], x[0]);
386 for(
int j=1; j<num_dimensions; j++) f *= RuleLocal::evalRaw<effrule>(order, point[j], x[j]);
390 std::vector<double> getNormalization()
const;
392 template<RuleLocal::erule effrule>
393 Data2D<int> buildUpdateMap(
double tolerance, TypeRefinement criteria,
int output,
const double *scale_correction)
const;
394 template<RuleLocal::erule effrule>
395 MultiIndexSet getRefinementCanidates(
double tolerance, TypeRefinement criteria,
int output,
const std::vector<int> &level_limits,
const double *scale_correction)
const;
397 template<RuleLocal::erule effrule>
398 bool addParent(
const int point[],
int direction,
const MultiIndexSet &exclude, Data2D<int> &destination)
const;
399 template<RuleLocal::erule effrule>
400 void addChild(
const int point[],
int direction,
const MultiIndexSet &exclude, Data2D<int> &destination)
const;
401 template<RuleLocal::erule effrule>
402 void addChildLimited(
const int point[],
int direction,
const MultiIndexSet &exclude,
const std::vector<int> &level_limits, Data2D<int> &destination)
const;
404 void clearGpuSurpluses();
405 void clearGpuBasisHierarchy();
408 int order, top_level;
410 Data2D<double> surpluses;
415 std::vector<int> roots;
416 std::vector<int> pntr;
417 std::vector<int> indx;
419 RuleLocal::erule effective_rule;
422 template<
int ord, TypeOneDRule crule,
typename T>
423 Data2D<T> encodeSupportForGPU(
const MultiIndexSet &work)
const{
424 Data2D<T> cpu_support(num_dimensions, work.getNumIndexes());
425 for(
int i=0; i<work.getNumIndexes(); i++){
426 const int* p = work.getIndex(i);
427 T *s = cpu_support.getStrip(i);
428 for(
int j=0; j<num_dimensions; j++){
430 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::pwc>(p[j]));
434 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::localp>(p[j]));
437 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::semilocalp>(p[j]));
440 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::localp0>(p[j]));
443 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::localpb>(p[j]));
446 if (ord == 2) s[j] *= s[j];
447 if ((crule == rule_localp) || (crule == rule_semilocalp))
if (p[j] == 0) s[j] =
static_cast<T
>(-1.0);
448 if ((crule == rule_localp) && (ord == 2)){
449 if (p[j] == 1) s[j] =
static_cast<T
>(-2.0);
450 else if (p[j] == 2) s[j] =
static_cast<T
>(-3.0);
452 if ((crule == rule_semilocalp) && (ord == 2)){
453 if (p[j] == 1) s[j] =
static_cast<T
>(-4.0);
454 else if (p[j] == 2) s[j] =
static_cast<T
>(-5.0);
456 if ((crule == rule_localpb) && (ord == 2)){
457 if (p[j] < 2) s[j] =
static_cast<T
>(-2.0);
464 std::optional<CudaLocalPolynomialData<double>>& getGpuCacheOverload(
double)
const{
return gpu_cache; }
465 std::optional<CudaLocalPolynomialData<float>>& getGpuCacheOverload(
float)
const{
return gpu_cachef; }
466 template<
typename T> std::optional<CudaLocalPolynomialData<T>>& getGpuCache()
const{
467 return getGpuCacheOverload(
static_cast<T
>(0.0));
469 template<
typename T>
void loadGpuBasis()
const;
470 template<
typename T>
void loadGpuHierarchy()
const;
471 template<
typename T>
void loadGpuSurpluses()
const;
472 mutable std::optional<CudaLocalPolynomialData<double>> gpu_cache;
473 mutable std::optional<CudaLocalPolynomialData<float>> gpu_cachef;
475 std::unique_ptr<SimpleConstructData> dynamic_values;
479template<>
struct GridReaderVersion5<GridLocalPolynomial>{
480 template<
typename iomode>
static void read(std::istream &is, GridLocalPolynomial *grid) {
481 grid->num_dimensions = IO::readNumber<iomode, int>(is);
482 grid->num_outputs = IO::readNumber<iomode, int>(is);
483 grid->order = IO::readNumber<iomode, int>(is);
484 grid->top_level = IO::readNumber<iomode, int>(is);
486 grid->effective_rule = RuleLocal::getEffectiveRule(grid->order, rule);
488 if (IO::readFlag<iomode>(is)) grid->points = MultiIndexSet(is, iomode());
489 if (std::is_same<iomode, IO::mode_ascii_type>::value){
490 if (IO::readFlag<iomode>(is))
491 grid->surpluses = IO::readData2D<iomode, double>(is, grid->num_outputs, grid->points.getNumIndexes());
492 if (IO::readFlag<iomode>(is)) grid->needed = MultiIndexSet(is, iomode());
494 if (IO::readFlag<iomode>(is)) grid->needed = MultiIndexSet(is, iomode());
495 if (IO::readFlag<iomode>(is))
496 grid->surpluses = IO::readData2D<iomode, double>(is, grid->num_outputs, grid->points.getNumIndexes());
498 int max_parents = [&]()->
int {
499 switch(grid->effective_rule) {
500 case RuleLocal::erule::pwc:
return RuleLocal::getMaxNumParents<RuleLocal::erule::pwc>();
501 case RuleLocal::erule::localp:
return RuleLocal::getMaxNumParents<RuleLocal::erule::localp>();
502 case RuleLocal::erule::semilocalp:
return RuleLocal::getMaxNumParents<RuleLocal::erule::semilocalp>();
503 case RuleLocal::erule::localp0:
return RuleLocal::getMaxNumParents<RuleLocal::erule::localp0>();
505 return RuleLocal::getMaxNumParents<RuleLocal::erule::localpb>();
509 if (IO::readFlag<iomode>(is))
510 grid->parents = IO::readData2D<iomode, int>(is, max_parents * grid->num_dimensions, grid->points.getNumIndexes());
512 size_t num_points = (size_t) ((grid->points.empty()) ? grid->needed.getNumIndexes() : grid->points.getNumIndexes());
513 grid->roots = std::vector<int>((
size_t) IO::readNumber<iomode, int>(is));
514 if (grid->roots.size() > 0){
515 IO::readVector<iomode>(is, grid->roots);
516 grid->pntr = IO::readVector<iomode, int>(is, num_points + 1);
517 if (grid->pntr[num_points] > 0){
518 grid->indx = IO::readVector<iomode, int>(is, grid->pntr[num_points]);
520 grid->indx = IO::readVector<iomode, int>(is, 1);
524 if (grid->num_outputs > 0) grid->values = StorageSet(is, iomode());
TypeOneDRule
Used to specify the one dimensional family of rules that induces the sparse grid.
Definition tsgEnumerates.hpp:288
@ rule_localp
Nested rule with a hierarchy of uniformly distributed nodes and functions with compact support.
Definition tsgEnumerates.hpp:365
@ rule_localpb
Variation of rule_localp focusing nodes on the boundary instead of the interior.
Definition tsgEnumerates.hpp:371
@ rule_localp0
Variation of rule_localp assuming the model is zero at the domain boundary.
Definition tsgEnumerates.hpp:367
@ rule_semilocalp
Variation of rule_localp using increased support in exchange for higher order basis (better for smoot...
Definition tsgEnumerates.hpp:369
void loadNeededValues(std::function< void(double const x[], double y[], size_t thread_id)> model, TasmanianSparseGrid &grid, size_t num_threads)
Loads the current grid with model values, does not perform any refinement.
Definition tsgLoadNeededValues.hpp:104
Encapsulates the Tasmanian Sparse Grid module.
Definition TasmanianSparseGrid.hpp:68