File: example_sparse_grids_05.cpp

package info (click to toggle)
tasmanian 8.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,852 kB
  • sloc: cpp: 34,523; python: 7,039; f90: 5,080; makefile: 224; sh: 64; ansic: 8
file content (154 lines) | stat: -rw-r--r-- 6,147 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

#include "Tasmanian.hpp"
#include <random>

using namespace std;

/*!
 * \internal
 * \file example_sparse_grids_05.cpp
 * \brief Examples for the Tasmanian Sparse Grid module.
 * \author Miroslav Stoyanov
 * \ingroup TasmanianSGExamples
 *
 * Tasmanian Sparse Grids Example 5.
 * \endinternal
 */

/*!
 * \ingroup TasmanianSGExamples
 * \addtogroup TasmanianSGExamples5 Tasmanian Sparse Grids module, example 5
 *
 * \par Example 5
 * Build a surrogate model using different adaptive schemes.
 */

/*!
 * \ingroup TasmanianSGExamples5
 * \brief Sparse Grids Example 5: adaptive surrogate modeling
 *
 * Example 4 demonstrates how to build a surrogate model in a direct "one-shot" process.
 * However, it is seldom the case that all model inputs have equal effect on the
 * model outputs, adaptive methods can construct much more reliable surrogates
 * with much fewer model evaluations.
 *
 * \snippet SparseGrids/Examples/example_sparse_grids_05.cpp SG_Example_05 example
 */
void sparse_grids_example_05(){
#ifndef __TASMANIAN_DOXYGEN_SKIP
//! [SG_Example_05 example]
#endif

    cout << "\n---------------------------------------------------------------------------------------------------\n";
    cout << std::scientific; cout.precision(4);
    cout << "Example 5: interpolate f(x,y) = exp(-x^2) * cos(y), using leja rule\n"
         << "           employ adaptive refinement to increase accuracy per samples\n";

    // define the model as a C++ lambda expression, the advantage of lambdas
    // is that they can wrap around much more complex models
    // see the documentation for TasGrid::loadNeededValues()
    int const num_inputs  = 2;
    int const num_outputs = 1;
    auto model = [](double const x[], double y[], size_t)->
        void{
            y[0] = std::exp(-x[0] * x[0]) * std::cos(x[1]);
        };

    // the accuracy of the surrogate models is measure from 1000 random reference points
    int const num_test_points = 1000;
    std::vector<double> test_points(num_test_points * num_inputs);
    std::minstd_rand park_miller(42);
    std::uniform_real_distribution<double> domain(-1.0, 1.0);
    for(auto &t : test_points) t = domain(park_miller);

    std::vector<double> reference_values(num_test_points * num_outputs);
    for(int i=0; i<num_test_points; i++)
        model(&test_points[num_inputs * i], &reference_values[num_outputs * i], 0);

    // computes the maximum error between the reference values and the grid interpolant
    auto test_grid = [&](TasGrid::TasmanianSparseGrid const &grid)->
        double{
            std::vector<double> result;
            grid.evaluateBatch(test_points, result);
            double diff = 0.0;
            for(int i=0; i<num_test_points; i++)
                diff = std::max(diff, std::abs(result[i] - reference_values[i]));
            return diff;
        };

    // we compare isotropic grid with 3 different refinement strategies
    int initial_level = 4;
    auto grid_isotropic = TasGrid::makeGlobalGrid(num_inputs, num_outputs, initial_level,
                                                  TasGrid::type_level, TasGrid::rule_leja);
    auto grid_iptotal = grid_isotropic; // using the same initial grid
    auto grid_icurved = grid_isotropic;
    auto grid_surplus = grid_isotropic;

    int budget = 100; // define budget for the number of points for the interpolant

    cout << setw(22) << "isotropic" << setw(22) << "iptotal"
         << setw(22) << "ipcurved" << setw(22) << "surplus\n";
    cout << setw(8) << "points" << setw(14) << "error"
         << setw(8) << "points" << setw(14) << "error"
         << setw(8) << "points" << setw(14) << "error"
         << setw(8) << "points" << setw(14) << "error\n";

    // loop while at least one grid hasn't exhausted the budget
    do{
        if (grid_isotropic.getNumLoaded() < budget){
            TasGrid::loadNeededValues(model, grid_isotropic, 0);
            cout << setw(8) << grid_isotropic.getNumLoaded()
                 << setw(14) << test_grid(grid_isotropic);

            // add an isotropic update until we increase the number of points
            int level = 0;
            while(grid_isotropic.getNumNeeded() == 0)
                grid_isotropic.updateGlobalGrid(++level, TasGrid::type_level);
        }else{
            cout << setw(22) << " ";
        }

        if (grid_iptotal.getNumLoaded() < budget){
            TasGrid::loadNeededValues(model, grid_iptotal, 0);
            cout << setw(8) << grid_iptotal.getNumLoaded() << setw(14) << test_grid(grid_iptotal);

           // set anisotropic total degree update using at least 10 new points
            grid_iptotal.setAnisotropicRefinement(TasGrid::type_iptotal, 10, 0);
        }else{
            cout << setw(22) << " ";
        }

        if (grid_icurved.getNumLoaded() < budget){
            TasGrid::loadNeededValues(model, grid_icurved, 0);
            auto w = grid_icurved.estimateAnisotropicCoefficients(TasGrid::type_ipcurved, 0);
            cout << setw(8) << grid_icurved.getNumLoaded() << setw(14) << test_grid(grid_icurved);

            // set anisotropic curved update using at least 10 new points
            grid_icurved.setAnisotropicRefinement(TasGrid::type_ipcurved, 10, 0);
        }else{
            cout << setw(22) << " ";
        }

        if (grid_surplus.getNumLoaded() < budget){
            TasGrid::loadNeededValues(model, grid_surplus, 0);
            cout << setw(8) << grid_surplus.getNumLoaded() << setw(14) << test_grid(grid_surplus);

            // set surplus based update using tolerance of 1.E-8
            grid_surplus.setSurplusRefinement(1.E-8, 0);
        }else{
            cout << setw(22) << " ";
        }
        cout << "\n";

    }while((grid_isotropic.getNumLoaded() < budget) ||
           (grid_iptotal.getNumLoaded() < budget) ||
           (grid_icurved.getNumLoaded() < budget) ||
           (grid_surplus.getNumLoaded() < budget));

    cout << "\nNote: the surplus refinement is sensitive to the non-monotonic coefficient decay\n"
         << "        and the choice of the tolerance.\n";

#ifndef __TASMANIAN_DOXYGEN_SKIP
//! [SG_Example_05 example]
#endif
}