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 :
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 bool isLocalPolynomial()
const override{
return true; }
49 void write(std::ostream &os,
bool iomode)
const override{
if (iomode == mode_ascii) write<mode_ascii>(os);
else write<mode_binary>(os); }
51 template<
bool iomode>
void write(std::ostream &os)
const;
53 TypeOneDRule getRule()
const override{
return RuleLocal::getRule(effective_rule); }
54 int getOrder()
const{
return order; }
56 template<RuleLocal::erule,
typename po
ints_mode>
57 void getPoints(
double *x)
const;
58 void getLoadedPoints(
double *x)
const override;
59 void getNeededPoints(
double *x)
const override;
60 void getPoints(
double *x)
const override;
62 template<RuleLocal::erule effrule>
63 void getQuadratureWeights(
double weights[])
const;
64 void getQuadratureWeights(
double weights[])
const override;
65 void getInterpolationWeights(
const double x[],
double weights[])
const override;
66 void getDifferentiationWeights(
const double x[],
double weights[])
const override;
70 void evaluate(
const double x[],
double y[])
const override;
71 void integrate(
double q[],
double *conformal_correction)
const override;
72 void differentiate(
const double x[],
double jacobian[])
const override;
74 void evaluateBatchOpenMP(
const double x[],
int num_x,
double y[])
const;
75 void evaluateBatch(
const double x[],
int num_x,
double y[])
const override;
77 void loadNeededValuesGPU(
const double *vals);
78 void evaluateGpuMixed(
const double x[],
int num_x,
double y[])
const;
79 void evaluateBatchGPU(
const double gpu_x[],
int cpu_num_x,
double gpu_y[])
const override;
80 void evaluateBatchGPU(
const float gpu_x[],
int cpu_num_x,
float gpu_y[])
const override;
81 template<
typename T>
void evaluateBatchGPUtempl(
const T gpu_x[],
int cpu_num_x, T gpu_y[])
const;
82 void evaluateHierarchicalFunctionsGPU(
const double gpu_x[],
int cpu_num_x,
double *gpu_y)
const override;
83 void buildSparseBasisMatrixGPU(
const double gpu_x[],
int cpu_num_x, GpuVector<int> &gpu_spntr, GpuVector<int> &gpu_sindx, GpuVector<double> &gpu_svals)
const;
84 void evaluateHierarchicalFunctionsGPU(
const float gpu_x[],
int cpu_num_x,
float *gpu_y)
const override;
85 void buildSparseBasisMatrixGPU(
const float gpu_x[],
int cpu_num_x, GpuVector<int> &gpu_spntr, GpuVector<int> &gpu_sindx, GpuVector<float> &gpu_svals)
const;
87 void setSurplusRefinement(
double tolerance, TypeRefinement criteria,
int output,
const std::vector<int> &level_limits,
const double *scale_correction);
88 void clearRefinement()
override;
89 void mergeRefinement()
override;
96 std::vector<double> getScaledCoefficients(
int output,
const double *scale_correction);
97 int removePointsByHierarchicalCoefficient(
double tolerance,
int output,
const double *scale_correction);
98 void removePointsByHierarchicalCoefficient(
int new_num_points,
int output,
const double *scale_correction);
104 int removeMappedPoints(std::vector<bool>
const &pmap);
106 void beginConstruction()
override;
107 void writeConstructionData(std::ostream &os,
bool)
const override;
108 void readConstructionData(std::istream &is,
bool)
override;
109 template<RuleLocal::erule effrule>
110 std::vector<double> getCandidateConstructionPoints(
double tolerance, TypeRefinement criteria,
int output, std::vector<int>
const &level_limits,
double const *scale_correction);
111 std::vector<double> getCandidateConstructionPoints(
double tolerance, TypeRefinement criteria,
int output, std::vector<int>
const &level_limits,
double const *scale_correction);
112 template<RuleLocal::erule effrule>
113 void loadConstructedPoint(
const double x[],
const std::vector<double> &y);
114 void loadConstructedPoint(
const double x[],
const std::vector<double> &y)
override;
115 template<RuleLocal::erule effrule>
116 void loadConstructedPoint(
const double x[],
int numx,
const double y[]);
117 void loadConstructedPoint(
const double x[],
int numx,
const double y[])
override;
118 void finishConstruction()
override;
120 void evaluateHierarchicalFunctions(
const double x[],
int num_x,
double y[])
const override;
121 std::vector<double> getSupport() const override final;
122 void setHierarchicalCoefficients(const
double c[]) override;
123 void integrateHierarchicalFunctions(
double integrals[]) const override;
125 void updateAccelerationData(AccelerationContext::ChangeType change) const override;
127 const
double* getSurpluses() const;
128 const
int* getNeededIndexes() const;
130 void buildSpareBasisMatrix(const
double x[],
int num_x,
int num_chunk, std::vector<
int> &spntr, std::vector<
int> &sindx, std::vector<
double> &svals) const;
131 void buildSpareBasisMatrixStatic(const
double x[],
int num_x,
int num_chunk,
int *spntr,
int *sindx,
double *svals) const;
132 int getSpareBasisMatrixNZ(const
double x[],
int num_x) const;
136 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);
139 void updateValues(
double const *vals);
144 template<RuleLocal::erule effrule>
145 std::vector<
int> getSubGraph(std::vector<
int> const &point) const;
148 template<RuleLocal::erule effrule>
149 void expandGrid(std::vector<
int> const &point, std::vector<
double> const &value);
152 template<RuleLocal::erule effrule>
153 std::vector<
int> getMultiIndex(const
double x[]);
156 template<RuleLocal::erule effrule>
157 void loadConstructedPoints();
160 template<RuleLocal::erule effrule>
161 void recomputeSurpluses();
163 void recomputeSurpluses();
180 template<RuleLocal::erule effrule>
181 void updateSurpluses(MultiIndexSet const &work,
int max_level, std::vector<
int> const &level, Data2D<
int> const &dagUp);
185 void applyTransformationTransposed(
double weights[], const MultiIndexSet &work, const std::vector<
int> &active_points) const;
186 template<
int mode, RuleLocal::erule effrule>
187 void applyTransformationTransposed(
double weights[], const MultiIndexSet &work, const std::vector<
int> &active_points) const;
189 void buildSparseMatrixBlockForm(const
double x[],
int num_x,
int num_chunk, std::vector<
int> &numnz,
190 std::vector<std::vector<
int>> &tindx, std::vector<std::vector<
double>> &tvals) const;
192 template<RuleLocal::erule eff_rule>
193 double evalBasisSupported(const
int point[], const
double x[],
bool &isSupported)
const{
194 double f = RuleLocal::evalSupport<eff_rule>(order, point[0], x[0], isSupported);
195 if (!isSupported)
return 0.0;
196 for(
int j=1; j<num_dimensions; j++){
197 f *= RuleLocal::evalSupport<eff_rule>(order, point[j], x[j], isSupported);
198 if (!isSupported)
return 0.0;
202 template<RuleLocal::erule effrule>
203 void diffBasisSupported(
const int point[],
const double x[],
double diff_values[],
bool &isSupported)
const{
205 for(
int i=0; i<num_dimensions; i++) diff_values[i] = 1.0;
206 bool isDimSupported =
false;
207 for(
int k=0; k<num_dimensions; k++) {
208 double fval = RuleLocal::evalSupport<effrule>(order, point[k], x[k], isDimSupported);
209 isSupported = isDimSupported or isSupported;
210 for(
int j=0; j<k; j++) diff_values[j] *= fval;
211 for(
int j=k+1; j<num_dimensions; j++) diff_values[j] *= fval;
213 for (
int k=0; k<num_dimensions; k++) {
214 diff_values[k] *= RuleLocal::diffSupport<effrule>(order, point[k], x[k], isDimSupported);
215 isSupported = isDimSupported or isSupported;
234 template<
int mode, RuleLocal::erule effrule>
235 void walkTree(
const MultiIndexSet &work,
const double x[], std::vector<int> &sindx, std::vector<double> &svals,
double *y)
const{
236 std::vector<int> monkey_count(top_level+1);
237 std::vector<int> monkey_tail(top_level+1);
241 std::vector<double> basis_derivative(num_dimensions);
243 for(
const auto &r : roots){
244 if (mode == 3 or mode == 4) {
245 diffBasisSupported<effrule>(work.getIndex(r), x, basis_derivative.data(), isSupported);
247 basis_value = evalBasisSupported<effrule>(work.getIndex(r), x, isSupported);
252 double const *s = surpluses.getStrip(r);
253 for(
int k=0; k<num_outputs; k++)
254 y[k] += basis_value * s[k];
255 }
else if (mode == 1 or mode == 2){
257 svals.push_back(basis_value);
258 }
else if (mode == 3){
259 double const *s = surpluses.getStrip(r);
260 for(
int k=0; k<num_outputs; k++)
261 for (
int d=0; d<num_dimensions; d++)
262 y[k * num_dimensions + d] += basis_derivative[d] * s[k];
265 for (
auto dx : basis_derivative)
271 monkey_count[0] = pntr[r];
273 while(monkey_count[0] < pntr[monkey_tail[0]+1]){
274 if (monkey_count[current] < pntr[monkey_tail[current]+1]){
275 int p = indx[monkey_count[current]];
276 if (mode == 3 or mode == 4){
277 diffBasisSupported<effrule>(work.getIndex(p), x, basis_derivative.data(), isSupported);
279 basis_value = evalBasisSupported<effrule>(work.getIndex(p), x, isSupported);
283 double const *s = surpluses.getStrip(p);
284 for(
int k=0; k<num_outputs; k++)
285 y[k] += basis_value * s[k];
286 }
else if (mode == 1 or mode == 2){
288 svals.push_back(basis_value);
289 }
else if (mode == 3){
290 double const *s = surpluses.getStrip(p);
291 for(
int k=0; k<num_outputs; k++)
292 for (
int d=0; d<num_dimensions; d++)
293 y[k * num_dimensions + d] += basis_derivative[d] * s[k];
296 for (
auto dx : basis_derivative)
299 monkey_tail[++current] = p;
300 monkey_count[current] = pntr[p];
302 monkey_count[current]++;
305 monkey_count[--current]++;
316 std::vector<int> map(sindx);
317 std::iota(map.begin(), map.end(), 0);
318 std::sort(map.begin(), map.end(), [&](
int a,
int b)->bool{ return (sindx[a] < sindx[b]); });
320 std::vector<int> idx = sindx;
321 std::vector<double> vls = svals;
322 std::transform(map.begin(), map.end(), sindx.begin(), [&](
int i)->int{ return idx[i]; });
323 std::transform(map.begin(), map.end(), svals.begin(), [&](
int i)->double{ return vls[i]; });
328 void walkTree(
const MultiIndexSet &work,
const double x[], std::vector<int> &sindx, std::vector<double> &svals,
double *y)
const{
329 switch(effective_rule) {
330 case RuleLocal::erule::pwc:
331 walkTree<mode, RuleLocal::erule::pwc>(work,x, sindx, svals, y);
333 case RuleLocal::erule::localp:
334 walkTree<mode, RuleLocal::erule::localp>(work,x, sindx, svals, y);
336 case RuleLocal::erule::semilocalp:
337 walkTree<mode, RuleLocal::erule::semilocalp>(work,x, sindx, svals, y);
339 case RuleLocal::erule::localp0:
340 walkTree<mode, RuleLocal::erule::localp0>(work,x, sindx, svals, y);
343 walkTree<mode, RuleLocal::erule::localpb>(work,x, sindx, svals, y);
348 template<RuleLocal::erule effrule>
349 double evalBasisRaw(
const int point[],
const double x[])
const {
350 double f = RuleLocal::evalRaw<effrule>(order, point[0], x[0]);
351 for(
int j=1; j<num_dimensions; j++) f *= RuleLocal::evalRaw<effrule>(order, point[j], x[j]);
355 std::vector<double> getNormalization()
const;
357 template<RuleLocal::erule effrule>
358 Data2D<int> buildUpdateMap(
double tolerance, TypeRefinement criteria,
int output,
const double *scale_correction)
const;
359 template<RuleLocal::erule effrule>
360 MultiIndexSet getRefinementCanidates(
double tolerance, TypeRefinement criteria,
int output,
const std::vector<int> &level_limits,
const double *scale_correction)
const;
362 template<RuleLocal::erule effrule>
363 bool addParent(
const int point[],
int direction,
const MultiIndexSet &exclude, Data2D<int> &destination)
const;
364 template<RuleLocal::erule effrule>
365 void addChild(
const int point[],
int direction,
const MultiIndexSet &exclude, Data2D<int> &destination)
const;
366 template<RuleLocal::erule effrule>
367 void addChildLimited(
const int point[],
int direction,
const MultiIndexSet &exclude,
const std::vector<int> &level_limits, Data2D<int> &destination)
const;
369 void clearGpuSurpluses();
370 void clearGpuBasisHierarchy();
373 int order, top_level;
375 Data2D<double> surpluses;
380 std::vector<int> roots;
381 std::vector<int> pntr;
382 std::vector<int> indx;
384 RuleLocal::erule effective_rule;
386 std::unique_ptr<SimpleConstructData> dynamic_values;
389 template<
int ord, TypeOneDRule crule,
typename T>
390 Data2D<T> encodeSupportForGPU(
const MultiIndexSet &work)
const{
391 Data2D<T> cpu_support(num_dimensions, work.getNumIndexes());
392 for(
int i=0; i<work.getNumIndexes(); i++){
393 const int* p = work.getIndex(i);
394 T *s = cpu_support.getStrip(i);
395 for(
int j=0; j<num_dimensions; j++){
397 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::pwc>(p[j]));
401 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::localp>(p[j]));
404 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::semilocalp>(p[j]));
407 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::localp0>(p[j]));
410 s[j] =
static_cast<T
>(RuleLocal::getSupport<RuleLocal::erule::localpb>(p[j]));
413 if (ord == 2) s[j] *= s[j];
414 if ((crule == rule_localp) || (crule == rule_semilocalp))
if (p[j] == 0) s[j] =
static_cast<T
>(-1.0);
415 if ((crule == rule_localp) && (ord == 2)){
416 if (p[j] == 1) s[j] =
static_cast<T
>(-2.0);
417 else if (p[j] == 2) s[j] =
static_cast<T
>(-3.0);
419 if ((crule == rule_semilocalp) && (ord == 2)){
420 if (p[j] == 1) s[j] =
static_cast<T
>(-4.0);
421 else if (p[j] == 2) s[j] =
static_cast<T
>(-5.0);
423 if ((crule == rule_localpb) && (ord == 2)){
424 if (p[j] < 2) s[j] =
static_cast<T
>(-2.0);
431 std::unique_ptr<CudaLocalPolynomialData<double>>& getGpuCacheOverload(
double)
const{
return gpu_cache; }
432 std::unique_ptr<CudaLocalPolynomialData<float>>& getGpuCacheOverload(
float)
const{
return gpu_cachef; }
433 template<
typename T> std::unique_ptr<CudaLocalPolynomialData<T>>& getGpuCache()
const{
434 return getGpuCacheOverload(
static_cast<T
>(0.0));
436 template<
typename T>
void loadGpuBasis()
const;
437 template<
typename T>
void loadGpuHierarchy()
const;
438 template<
typename T>
void loadGpuSurpluses()
const;
439 mutable std::unique_ptr<CudaLocalPolynomialData<double>> gpu_cache;
440 mutable std::unique_ptr<CudaLocalPolynomialData<float>> gpu_cachef;
444template<>
struct GridReaderVersion5<GridLocalPolynomial>{
445 template<
typename iomode>
static std::unique_ptr<GridLocalPolynomial> read(AccelerationContext
const *acc, std::istream &is){
446 std::unique_ptr<GridLocalPolynomial> grid = Utils::make_unique<GridLocalPolynomial>(acc);
448 grid->num_dimensions = IO::readNumber<iomode, int>(is);
449 grid->num_outputs = IO::readNumber<iomode, int>(is);
450 grid->order = IO::readNumber<iomode, int>(is);
451 grid->top_level = IO::readNumber<iomode, int>(is);
453 grid->effective_rule = RuleLocal::getEffectiveRule(grid->order, rule);
455 if (IO::readFlag<iomode>(is)) grid->points = MultiIndexSet(is, iomode());
456 if (std::is_same<iomode, IO::mode_ascii_type>::value){
457 if (IO::readFlag<iomode>(is))
458 grid->surpluses = IO::readData2D<iomode, double>(is, grid->num_outputs, grid->points.getNumIndexes());
459 if (IO::readFlag<iomode>(is)) grid->needed = MultiIndexSet(is, iomode());
461 if (IO::readFlag<iomode>(is)) grid->needed = MultiIndexSet(is, iomode());
462 if (IO::readFlag<iomode>(is))
463 grid->surpluses = IO::readData2D<iomode, double>(is, grid->num_outputs, grid->points.getNumIndexes());
465 int max_parents = [&]()->
int {
466 switch(grid->effective_rule) {
467 case RuleLocal::erule::pwc:
return RuleLocal::getMaxNumParents<RuleLocal::erule::pwc>();
468 case RuleLocal::erule::localp:
return RuleLocal::getMaxNumParents<RuleLocal::erule::localp>();
469 case RuleLocal::erule::semilocalp:
return RuleLocal::getMaxNumParents<RuleLocal::erule::semilocalp>();
470 case RuleLocal::erule::localp0:
return RuleLocal::getMaxNumParents<RuleLocal::erule::localp0>();
472 return RuleLocal::getMaxNumParents<RuleLocal::erule::localpb>();
476 if (IO::readFlag<iomode>(is))
477 grid->parents = IO::readData2D<iomode, int>(is, max_parents * grid->num_dimensions, grid->points.getNumIndexes());
479 size_t num_points = (size_t) ((grid->points.empty()) ? grid->needed.getNumIndexes() : grid->points.getNumIndexes());
480 grid->roots = std::vector<int>((
size_t) IO::readNumber<iomode, int>(is));
481 if (grid->roots.size() > 0){
482 IO::readVector<iomode>(is, grid->roots);
483 grid->pntr = IO::readVector<iomode, int>(is, num_points + 1);
484 if (grid->pntr[num_points] > 0){
485 grid->indx = IO::readVector<iomode, int>(is, grid->pntr[num_points]);
487 grid->indx = IO::readVector<iomode, int>(is, 1);
491 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:285
@ rule_localp
Nested rule with a hierarchy of uniformly distributed nodes and functions with compact support.
Definition tsgEnumerates.hpp:362
@ rule_localpb
Variation of rule_localp focusing nodes on the boundary instead of the interior.
Definition tsgEnumerates.hpp:368
@ rule_localp0
Variation of rule_localp assuming the model is zero at the domain boundary.
Definition tsgEnumerates.hpp:364
@ rule_semilocalp
Variation of rule_localp using increased support in exchange for higher order basis (better for smoot...
Definition tsgEnumerates.hpp:366
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