pax_global_header00006660000000000000000000000064147055117620014522gustar00rootroot0000000000000052 comment=86046564a0d3da9a98aae5111d617bcad09de8d0 TASMANIAN-8.1/000077500000000000000000000000001470551176200127055ustar00rootroot00000000000000TASMANIAN-8.1/.github/000077500000000000000000000000001470551176200142455ustar00rootroot00000000000000TASMANIAN-8.1/.github/workflows/000077500000000000000000000000001470551176200163025ustar00rootroot00000000000000TASMANIAN-8.1/.github/workflows/build-macos.yaml000066400000000000000000000027241470551176200213720ustar00rootroot00000000000000name: build-macos # Controls when the action will run on: push: pull_request: workflow_dispatch: # trigger the workflow manually # # trigger the workflow on schedule # # https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#scheduled-events # schedule: # - cron: '* * * * *' # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: build: runs-on: ${{ matrix.runner }} continue-on-error: false strategy: matrix: runner: [macos-14] compiler: [clang++] steps: - uses: actions/checkout@v2 - name: Install requirements run: > python3 -m venv tastest && source ./tastest/bin/activate && python3 -m pip install pip --upgrade && python3 -m pip install numpy - name: Build run: > source ./tastest/bin/activate && rm -rf build && mkdir -p build && cd build && cmake -D CMAKE_INSTALL_PREFIX=./TasmanianInstall -D CMAKE_CXX_FLAGS="-O3 -Wall -Wextra -Wshadow -pedantic" -D CMAKE_CXX_COMPILER=${{ matrix.compiler }} -D Tasmanian_ENABLE_FORTRAN=OFF -D Tasmanian_ENABLE_RECOMMENDED=ON -D Tasmanian_TESTS_OMP_NUM_THREADS=3 .. && make -j3 - name: Test run: cd build && ctest -V --no-compress-output -T Test - name: Install run: cd build && make install && make test_install TASMANIAN-8.1/.github/workflows/build-ubuntu.yaml000066400000000000000000000026571470551176200216170ustar00rootroot00000000000000name: build-ubuntu # Controls when the action will run on: push: pull_request: workflow_dispatch: # trigger the workflow manually # # trigger the workflow on schedule # # https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#scheduled-events # schedule: # - cron: '* * * * *' # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: build: runs-on: ${{ matrix.runner }} continue-on-error: false strategy: matrix: runner: [ubuntu-20.04, ubuntu-22.04] compiler: [clang++, g++] fortran_compiler: [gfortran] steps: - uses: actions/checkout@v2 - name: Install requirements run: python3 -m pip install numpy --user - name: Build run: > rm -rf build && mkdir -p build && cd build && cmake -D CMAKE_INSTALL_PREFIX=./TasmanianInstall -D CMAKE_CXX_FLAGS="-O3 -Wall -Wextra -Wshadow -pedantic" -D CMAKE_CXX_COMPILER=${{ matrix.compiler }} -D CMAKE_Fortran_COMPILER=${{ matrix.fortran_compiler }} -D Tasmanian_ENABLE_RECOMMENDED=ON -D Tasmanian_ENABLE_FORTRAN=ON -D Tasmanian_TESTS_OMP_NUM_THREADS=4 .. && make -j4 - name: Test run: cd build && ctest -j4 -V --no-compress-output -T Test - name: Install run: cd build && make install && make test_install TASMANIAN-8.1/.github/workflows/build-windows.yaml000066400000000000000000000023661470551176200217640ustar00rootroot00000000000000name: build-windows # Controls when the action will run on: push: pull_request: workflow_dispatch: # trigger the workflow manually # # trigger the workflow on schedule # # https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#scheduled-events # schedule: # - cron: '* * * * *' # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: build: runs-on: ${{ matrix.runner }} continue-on-error: false strategy: matrix: runner: [windows-2019, windows-2022] steps: - uses: actions/checkout@v2 - name: Install requirements run: python -m pip install numpy - name: Build run: > md build -ea 0 && cd build && Get-ChildItem * -Recurse | Remove-Item && cmake -D CMAKE_INSTALL_PREFIX=./TasmanianInstall -D CMAKE_CXX_FLAGS="/O2" -D Tasmanian_ENABLE_RECOMMENDED=ON -D BUILD_SHARED_LIBS=ON -D Tasmanian_TESTS_OMP_NUM_THREADS=4 .. && cmake --build . --config Release --parallel 4 - name: Test run: cd build && ctest -C Release - name: Install run: cd build && cmake --build . --config Release --target install TASMANIAN-8.1/Addons/000077500000000000000000000000001470551176200141155ustar00rootroot00000000000000TASMANIAN-8.1/Addons/CMakeLists.txt000066400000000000000000000114251470551176200166600ustar00rootroot00000000000000######################################################################## # Addon templates and related tests and interface options ######################################################################## add_library(Tasmanian_addons INTERFACE) foreach(_tsg_file tsgAddonsCommon.hpp tsgMPIScatterGrid.hpp tsgMPIScatterDream.hpp tsgMPISampleDream.hpp tsgLoadNeededValues.hpp tsgLoadUnstructuredPoints.hpp tsgCandidateManager.hpp tsgConstructSurrogate.hpp tsgMPIConstructGrid.hpp tsgExoticQuadrature.hpp TasmanianAddons.hpp) target_sources(Tasmanian_addons INTERFACE $ $) endforeach() target_include_directories(Tasmanian_addons INTERFACE $) target_link_libraries(Tasmanian_addons INTERFACE Tasmanian_libdream) if (Tasmanian_ENABLE_PYTHON) # the C addons are used by Python add_library(Tasmanian_caddons SHARED tsgCExoticQuadrature.cpp tsgCLoadNeededValues.cpp tsgCConstructSurrogate.cpp tsgCLoadUnstructuredPoints.cpp) target_link_libraries(Tasmanian_caddons Tasmanian_addons) set_target_properties(Tasmanian_caddons PROPERTIES OUTPUT_NAME "tasmaniancaddons" INSTALL_RPATH "${Tasmanian_rpath}" SOVERSION ${Tasmanian_VERSION_MAJOR} VERSION ${PROJECT_VERSION}) install(TARGETS Tasmanian_caddons EXPORT "${Tasmanian_export_name}" RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib") endif() # The Tasmanian MPI capabilities are templated into the Addons if (Tasmanian_ENABLE_MPI) target_link_libraries(Tasmanian_addons INTERFACE MPI::MPI_CXX) add_executable(Tasmanian_mpitester testMPI.cpp testMPI.hpp testMPIDream.hpp) add_test(MPISparseGridsIO ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/mpitester ${MPIEXEC_POSTFLAGS}) list(APPEND Tasmanian_addons_executables "mpitester") list(APPEND Tasmanian_addons_tests "MPISparseGridsIO") endif() # test for non-MPI capabilities add_executable(Tasmanian_addontester testAddons.cpp testConstructSurrogate.hpp testLoadUnstructured.hpp) add_test(AddonTests addontester -gpuid ${Tasmanian_TESTS_GPU_ID}) list(APPEND Tasmanian_addons_executables "addontester") list(APPEND Tasmanian_addons_tests "AddonTests") # set properties for all executable targets foreach(_tsg_exec ${Tasmanian_addons_executables}) set_target_properties(Tasmanian_${_tsg_exec} PROPERTIES OUTPUT_NAME "${_tsg_exec}" CXX_EXTENSIONS OFF) Tasmanian_rpath_target(TARGET Tasmanian_${_tsg_exec} USE_CURRENT COMPONENTS SparseGrids DREAM) target_link_libraries(Tasmanian_${_tsg_exec} Tasmanian_addons Tasmanian_libdream) endforeach() unset(_tsg_exec) # cheap models have huge random variation in time-per-sample which can cause tests to fail # make sure other tests are not holding resources and making things even worse set_tests_properties(${Tasmanian_addons_tests} PROPERTIES RUN_SERIAL ON) Tasmanian_set_test_properties(TESTS ${Tasmanian_addons_tests}) # Windows specific support (DLL export/import directives and names) if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if (TARGET Tasmanian_caddons) set_target_properties(Tasmanian_caddons PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) endif() if (BUILD_SHARED_LIBS) set(Tasmanian_MSVC_PATH_STRING "${CMAKE_CURRENT_BINARY_DIR}/../SparseGrids/Release;${CMAKE_CURRENT_BINARY_DIR}/../SparseGrids/Debug") set(Tasmanian_MSVC_PATH_STRING "${Tasmanian_MSVC_PATH_STRING};${CMAKE_CURRENT_BINARY_DIR}/../DREAM/Release;${CMAKE_CURRENT_BINARY_DIR}/../DREAM/Debug;$ENV{PATH}") string(REPLACE ";" "\\;" Tasmanian_MSVC_PATH_STRING "${Tasmanian_MSVC_PATH_STRING}") set_tests_properties(${Tasmanian_addons_tests} PROPERTIES ENVIRONMENT "PATH=${Tasmanian_MSVC_PATH_STRING}") endif() endif() # install directives target_include_directories(Tasmanian_addons INTERFACE $) get_target_property(_tsg_sources Tasmanian_addons INTERFACE_SOURCES) install(FILES ${_tsg_sources} DESTINATION include) install(TARGETS Tasmanian_addons EXPORT "${Tasmanian_export_name}" PUBLIC_HEADER DESTINATION include) # cleanup unset(_tsg_sources) unset(Tasmanian_addons_executables) unset(Tasmanian_addons_tests) TASMANIAN-8.1/Addons/TasmanianAddons.hpp000066400000000000000000000063071470551176200177000ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_HPP #define __TASMANIAN_ADDONS_HPP /*! * \internal * \file TasmanianAddons.hpp * \brief Header to include add addon templates. * \author Miroslav Stoyanov * \ingroup TasmanianAddons * * All addon templates are included with this single header. * \endinternal */ #include "tsgLoadUnstructuredPoints.hpp" #include "tsgMPISampleDream.hpp" #include "tsgExoticQuadrature.hpp" /*! * \defgroup TasmanianAddons Additional Capabilities * * \par Extra Capabilities * The Addon module of Tasmanian offers a series of templates that offer * additional capabilities not necessarily included in the core modules. * The templates sit in a separate module for various reasons, e.g., * - some methods are hard to classify or address fringe use cases * - the templates depend on third-party libraries and should not overwhelm * the core modules with dependencies */ #endif TASMANIAN-8.1/Addons/testAddons.cpp000066400000000000000000000122371470551176200167360ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "testConstructSurrogate.hpp" #include "testLoadUnstructured.hpp" #include "testExoticQuadrature.hpp" #include "testCustomTabulated.hpp" void debugTest() { cout << "Debug Test (callable from the CMake build folder)" << endl; cout << "Put testing code here and call with ./Addons/addontester debug" << endl; } int main(int argc, char const **argv){ std::deque args = stringArgs(argc, argv); bool debug = false; bool pass_all = true; bool verbose = false; int gpuid = -1; while(not args.empty()){ if (args.front() == "debug") debug = true; if (hasInfo(args.front())) verbose = true; if (hasGpuID(args.front())){ args.pop_front(); gpuid = getGpuID(args); } args.pop_front(); } if (debug){ debugTest(); return 0; } cout << "\n\n"; cout << "---------------------------------------------------------------------" << endl; cout << " Tasmanian Addons Module: Functionality Test" << endl; cout << "---------------------------------------------------------------------" << endl << endl; bool pass = testConstructSurrogate(verbose); cout << std::setw(40) << "Automated construction" << std::setw(10) << ((pass) ? "Pass" : "FAIL") << endl; pass_all = pass_all && pass; #if defined(Tasmanian_ENABLE_BLAS) || defined(Tasmanian_ENABLE_GPU) pass = true; pass = testLoadUnstructuredL2(verbose, gpuid); cout << std::setw(40) << "Unstructured construction" << std::setw(10) << ((pass) ? "Pass" : "FAIL") << endl; pass_all = pass_all && pass; #else cout << std::setw(40) << "Unstructured construction" << std::setw(10) << "skipping" << endl; gpuid *= 2; // no op to register the use of gpuid #endif // Tests for Exotic Quadrature. pass = true; pass = testExoticQuadrature(); cout << std::setw(40) << "Exotic quadrature" << std::setw(10) << ((pass) ? "Pass" : "FAIL") << endl; pass_all = pass_all && pass; // Tests for manipulating CustomTabulated objects. pass = true; pass = testCustomTabulated(); cout << std::setw(40) << "CustomTabulated manipulation" << std::setw(10) << ((pass) ? "Pass" : "FAIL") << endl; pass_all = pass_all && pass; cout << "\n"; if (pass){ cout << "---------------------------------------------------------------------" << endl; cout << " All Tests Completed Successfully" << endl; cout << "---------------------------------------------------------------------" << endl << endl; }else{ cout << "FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL" << endl; cout << " Some Tests Have Failed" << endl; cout << "FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL" << endl << endl; } return ((pass_all) ? 0 : 1); } TASMANIAN-8.1/Addons/testConstructSurrogate.hpp000066400000000000000000000406111470551176200214100ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "TasmanianAddons.hpp" #include "gridtestCLICommon.hpp" #include using std::cout; using std::setw; //! \brief Runs tests and throws if the surrogates do not match to the given tolerance. inline void compareGrids(double tolerance, TasGrid::TasmanianSparseGrid const &a, TasGrid::TasmanianSparseGrid const &b, bool check_num_points){ if (a.getNumDimensions() != b.getNumDimensions()) throw std::runtime_error("grids have wrong dimensions"); if (a.getNumOutputs() != b.getNumOutputs()) throw std::runtime_error("grids have wrong outputs"); if (check_num_points){ // some tests have a random number of points if (a.getNumPoints() != b.getNumPoints()){ cout << "number of points = " << a.getNumPoints() << " " << b.getNumPoints() << endl; throw std::runtime_error("grids have wrong number of points"); } } std::minstd_rand park_miller(77); std::uniform_real_distribution unif(-1.0, 1.0); std::vector test_points(2 * 1000); for(auto &t : test_points) t = unif(park_miller); std::vector resa, resb; // reference and actual result a.evaluateBatch(test_points, resa); b.evaluateBatch(test_points, resb); double err = 0.0; for(auto ia = resa.begin(), ib = resb.begin(); ia != resa.end(); ia++, ib++) err = std::max(err, std::abs(*ia - *ib)); if (err > tolerance){ cout << "difference = " << err << " expected = " << tolerance << endl; throw std::runtime_error("grids have outputs that differ by more than the tolerance"); } } //! \brief Simple sequential construction for reference purposes. void simpleSequentialConstruction(std::function const &x, std::vector &y, size_t)> model, size_t max_num_samples, size_t num_parallel_jobs, TasmanianSparseGrid &grid, std::function(TasGrid::TasmanianSparseGrid&)> get_candidates){ if (!grid.isUsingConstruction()) grid.beginConstruction(); auto candidates = get_candidates(grid); while(!candidates.empty() && (grid.getNumLoaded() < (int) max_num_samples)){ CompleteStorage storage(grid.getNumDimensions()); size_t num_samples = std::min(std::min(num_parallel_jobs, max_num_samples - grid.getNumLoaded()), candidates.size() / grid.getNumDimensions()); for(size_t i=0; i x(&candidates[i*grid.getNumDimensions()], &candidates[i*grid.getNumDimensions()] + grid.getNumDimensions()); std::vector y(grid.getNumOutputs()); model(x, y, i); storage.add(x, y); } storage.load(grid); auto pnts = grid.getLoadedPoints(); candidates = get_candidates(grid); } grid.finishConstruction(); } //! \brief Reference construction for localp grids. void simpleSequentialConstruction(std::function const &x, std::vector &y, size_t)> model, size_t max_num_samples, size_t num_parallel_jobs, TasmanianSparseGrid &grid, double tolerance, TypeRefinement criteria, int output = -1, std::vector const &level_limits = std::vector(), std::vector const &scale_correction = std::vector()){ simpleSequentialConstruction(model, max_num_samples, num_parallel_jobs, grid, [&](TasGrid::TasmanianSparseGrid& g)->std::vector{ return g.getCandidateConstructionPoints(tolerance, criteria, output, level_limits, scale_correction); }); } //! \brief Reference construction for anisotropic refinement. void simpleSequentialConstruction(std::function const &x, std::vector &y, size_t)> model, size_t max_num_samples, size_t num_parallel_jobs, TasmanianSparseGrid &grid, TypeDepth type, int output, std::vector const &level_limits = std::vector()){ simpleSequentialConstruction(model, max_num_samples, num_parallel_jobs, grid, [&](TasGrid::TasmanianSparseGrid& g)->std::vector{ return g.getCandidateConstructionPoints(type, output, level_limits); }); } //! \brief Tests the templates for automated construction. bool testConstructSurrogate(bool verbose){ std::atomic_int last; last = -1; constexpr unsigned int delay_on_lock = 2; // test the simple loadNeededPoints() auto model_trig = [&](double const x[], double y[], size_t)->void{ y[0] = std::sin(x[0]) * std::cos(x[1]); }; auto model_trig_vec = [&](std::vector const &x, std::vector &y, size_t id)->void{ model_trig(x.data(), y.data(), id); }; auto grid = TasGrid::makeSequenceGrid(2, 1, 9, TasGrid::type_level, TasGrid::rule_leja); auto reference_grid = grid; auto points = reference_grid.getPoints(); std::vector values(reference_grid.getNumPoints()); for(size_t i=0; i(model_trig, grid, 128); // sequential version ignores the num_threads compareGrids(1.E-10, grid, reference_grid, true); grid.loadNeededPoints(std::vector(reference_grid.getNumPoints(), -1.0)); // set wrong values loadNeededPoints(model_trig, grid, 4); // reload the needed points using 4 threads compareGrids(1.E-10, grid, reference_grid, true); grid = TasGrid::makeSequenceGrid(2, 1, 9, TasGrid::type_level, TasGrid::rule_leja); loadNeededPoints(model_trig_vec, grid, 4); compareGrids(1.E-10, grid, reference_grid, true); if (verbose) cout << std::setw(40) << "simple load values" << std::setw(10) << "Pass" << endl; // parallel construction is susceptible to order of execution, number of points and which points may change from one run to the next auto model_exp_seq = [&](std::vector const &x, std::vector &y, size_t)->void{ y = {std::exp(x[0] + x[1])}; }; auto model_exp = [&](std::vector const &x, std::vector &y, size_t id)->void{ model_exp_seq(x, y, id); if (last == (int) id) std::this_thread::sleep_for(std::chrono::milliseconds(delay_on_lock)); else last = (int) id; }; auto model_exp2 = [&](std::vector const &x, std::vector &y, size_t id)->void{ if (x.size() == 2) y = {std::exp(x[0] + x[1])}; // one sample else y = {std::exp(x[0] + x[1]), std::exp(x[2] + x[3])}; // two samples if (last == (int) id) std::this_thread::sleep_for(std::chrono::milliseconds(delay_on_lock)); else last = (int) id; }; // two samples grid = TasGrid::makeLocalPolynomialGrid(2, 1, 3, 2); reference_grid = grid; // Basic test, run until grid points are exhausted, number of points can still vary // due to child surplus being computed before or after the parent point has completed TasGrid::constructSurrogate (model_exp, std::numeric_limits::max(), 2, 1, grid, 1.E-4, TasGrid::refine_classic); // parallel simpleSequentialConstruction(model_exp, 300, 2, reference_grid, 1.E-4, TasGrid::refine_classic); compareGrids(5.E-4, grid, reference_grid, false); if (verbose) cout << std::setw(40) << "parallel localp unlimited budget" << std::setw(10) << "Pass" << endl; grid = TasGrid::makeLocalPolynomialGrid(2, 1, 3, 2); TasGrid::constructSurrogate (model_exp2, std::numeric_limits::max(), 2, 2, grid, 1.E-4, TasGrid::refine_classic); // parallel, batch 2 compareGrids(5.E-4, grid, reference_grid, false); if (verbose) cout << std::setw(40) << "parallel localp batch" << std::setw(10) << "Pass" << endl; // Similar test, the number of points must match, but the actual points can be different // compare the grids by how similar they are to each other grid = TasGrid::makeLocalPolynomialGrid(2, 1, 3, 1); reference_grid = grid; TasGrid::constructSurrogate (model_exp, 500, 4, 1, grid, 1.E-4, TasGrid::refine_classic); // parallel, limit points simpleSequentialConstruction(model_exp, 500, 4, reference_grid, 1.E-4, TasGrid::refine_classic); compareGrids(5.E-3, grid, reference_grid, true); if (verbose) cout << std::setw(40) << "parallel localp limited budget" << std::setw(10) << "Pass" << endl; // Sequential test, checks the simpler algorithm, this should be deterministic grid = TasGrid::makeLocalPolynomialGrid(2, 1, 3, 2); reference_grid = grid; TasGrid::constructSurrogate (model_exp_seq, std::numeric_limits::max(), 2, 1, grid, 1.E-4, TasGrid::refine_classic); // sequential simpleSequentialConstruction(model_exp, 300, 2, reference_grid, 1.E-4, TasGrid::refine_classic); compareGrids(1.E-9, grid, reference_grid, true); if (verbose) cout << std::setw(40) << "sequential localp limited budget" << std::setw(10) << "Pass" << endl; // The construction algorithm is the same, but check if the getCandidateConstructionPoints() lambda works right auto model_aniso_seq = [&](std::vector const &x, std::vector &y, size_t)->void{ y = {std::exp(x[0] + 0.1 * x[1])}; }; auto model_aniso = [&](std::vector const &x, std::vector &y, size_t id)->void{ model_aniso_seq(x, y, id); if (last == (int) id) std::this_thread::sleep_for(std::chrono::milliseconds(delay_on_lock)); else last = (int) id; }; grid = TasGrid::makeGlobalGrid(2, 1, 3, TasGrid::type_level, TasGrid::rule_rleja); reference_grid = grid; TasGrid::constructSurrogate (model_aniso, 200, 3, 1, grid, TasGrid::type_iptotal, 0); // parallel simpleSequentialConstruction(model_aniso, 200, 2, reference_grid, TasGrid::type_iptotal, 0); compareGrids(1.E-8, grid, reference_grid, true); if (verbose) cout << std::setw(40) << "parallel anisotropic rleja" << std::setw(10) << "Pass" << endl; // additional fluctuation of number of points can happen due to not enough points to complete a tensor // nevertheless the grid accuracy should match reasonably well grid = TasGrid::makeGlobalGrid(2, 1, 3, TasGrid::type_level, TasGrid::rule_clenshawcurtis); reference_grid = grid; TasGrid::constructSurrogate (model_aniso, 400, 3, 1, grid, TasGrid::type_iptotal, 0); // parallel simpleSequentialConstruction(model_aniso, 400, 2, reference_grid, TasGrid::type_iptotal, 0); compareGrids(5.E-4, grid, reference_grid, false); if (verbose) cout << std::setw(40) << "parallel anisotropic global" << std::setw(10) << "Pass" << endl; // fix the weights, the computed grid must be very similar to the direct anisotropic make grid // i.e., the "most important" points are defined the same way through the user provided anisotropic weights // the atomic trick is used to ensure that no thread lags and holds important samples that affect the estimate for the anisotropy last = -1; std::vector aweights = {1, 2}; reference_grid = TasGrid::makeSequenceGrid(2, 1, 9, TasGrid::type_level, TasGrid::rule_leja, aweights); loadNeededPoints(model_aniso_seq, reference_grid, 0); grid = TasGrid::makeSequenceGrid(2, 1, 1, TasGrid::type_level, TasGrid::rule_leja); TasGrid::constructSurrogate (model_aniso, reference_grid.getNumLoaded(), 4, 1, grid, TasGrid::type_iptotal, aweights); // parallel compareGrids(5.E-7, grid, reference_grid, true); if (verbose) cout << std::setw(40) << "parallel weighted sequence" << std::setw(10) << "Pass" << endl; // test checkpoint-restart std::atomic_int num_good; num_good = 0; auto model_crash = [&](std::vector const &x, std::vector &y, size_t)->void{ y = {std::exp(x[0] + 0.1 * x[1])}; num_good++; if (num_good == 10) throw std::runtime_error("test fail"); // simulate a crash on iteration 10 }; grid = TasGrid::makeSequenceGrid(2, 1, 1, TasGrid::type_level, TasGrid::rule_leja); std::remove("checkpoint"); // make sure the checkpoint filename is not present (e.g., left after an earlier crash) try{ TasGrid::constructSurrogate (model_crash, reference_grid.getNumLoaded(), 2, 1, grid, TasGrid::type_iptotal, aweights, {}, "checkpoint"); std::cout << "ERROR: testConstructSurrogate() could not simulate a crash." << std::endl; return false; }catch(std::runtime_error &){ //cout << "Error caught!" << endl; grid = TasGrid::makeSequenceGrid(2, 1, 1, TasGrid::type_level, TasGrid::rule_rleja); // recovery should change the rule TasGrid::constructSurrogate (model_crash, reference_grid.getNumLoaded(), 2, 1, grid, TasGrid::type_iptotal, aweights, {}, "checkpoint"); if (grid.getRule() != rule_leja) throw std::runtime_error("Failed recovery from crash, wrong rule."); compareGrids(1.E-9, grid, reference_grid, true); if (verbose) cout << std::setw(40) << "parallel resilient sequence" << std::setw(10) << "Pass" << endl; } if (std::remove("checkpoint") != 0) throw std::runtime_error("Could not delete the 'checkpoint' file, the file must exists after the test."); return true; } TASMANIAN-8.1/Addons/testCustomTabulated.hpp000066400000000000000000000121151470551176200206260ustar00rootroot00000000000000/* * Copyright (c) 2021, Miroslav Stoyanov & William Kong * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND * IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE * OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL * ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES * RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING * FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "TasmanianAddons.hpp" // Test getSubrules(). inline bool testGetSubrules() { bool passed = true; // Level == 0 TasGrid::CustomTabulated empty_ct; TasGrid::CustomTabulated empty_sub_ct = TasGrid::getSubrules(empty_ct, 0, 2, "Empty rules"); if (empty_sub_ct.getNumLevels() != 0) { passed = false; } // Level >= 1 std::vector n_vec = {1, 2, 10}; std::vector start_index_vec = {0, 1, 4}; std::vector stride_vec = {1, 2, 3}; for (auto n : n_vec) { // Create the full CustomTabulated instance with n levels. std::vector num_nodes(n), precision(n); std::vector> nodes(n), weights(n); for (int i=0; i w, x, sub_w, sub_x; ct.getWeightsNodes(level, w, x); sub_ct.getWeightsNodes(sub_level, sub_w, sub_x); for (int i=0; i < ct.getNumPoints(level); i++) { if (w[i] != sub_w[i] || x[i] != sub_x[i]) { passed = false; } } sub_level++; } if (sub_ct.getNumLevels() != sub_level) { passed = false; } } } } return passed; } // Main wrapper inline bool testCustomTabulated() { bool passed = true; passed = passed && testGetSubrules() ; return passed; } TASMANIAN-8.1/Addons/testExoticQuadrature.hpp000066400000000000000000000256551470551176200210340ustar00rootroot00000000000000/* * Copyright (c) 2021, Miroslav Stoyanov & William Kong * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND * IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE * OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL * ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES * RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING * FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "TasmanianAddons.hpp" #include "gridtestCLICommon.hpp" #include // Test the output of getGaussNodesAndWeights(). inline bool testNodeAndWeightSizes() { bool passed = true; std::vector> points_cache, weights_cache; int nref = 5; std::vector ref_weights(nref), ref_points(nref); TasGrid::OneDimensionalNodes::getGaussLegendre(nref, ref_weights, ref_points); // n = 1, 2, 5 std::vector n_vec = {1, 2, 5}; for (auto n : n_vec) { TasGrid::getGaussNodesAndWeights(n, ref_points, ref_weights, points_cache, weights_cache); if (static_cast(points_cache.size()) != n) { std::cout << "ERROR: Test failed in testNodeAndWeightSizes() for n = " << n << std::endl; passed = false; } if (static_cast(weights_cache.size()) != n) { std::cout << "ERROR: Test failed in testNodeAndWeightSizes() for n = " << n << std::endl; passed = false; } } return passed; } // Test the attributes of the output of getExoticQuadrature(). inline bool testBasicAttributes() { bool passed = true; const int n = 3; const int nref = 11; const char *descr = "TEST_DESCRIPTION"; auto sinc = [](double x) -> double {return (x == 0.0 ? 1.0 : sin(x) / (x));}; // Different behaviors expected for shift == 0.0 vs shift != 0.0. std::vector shifts = {0.0, 1.0}; for (auto shift : shifts) { TasGrid::CustomTabulated ct = TasGrid::getExoticQuadrature(n, shift, sinc, nref, descr); if (strcmp(ct.getDescription(), descr) != 0) { std::cout << "ERROR: Test failed in testCtAttributes() for shift = " << shift << " on getDescription()"<< std::endl; passed = false; } if (ct.getNumLevels() != n) { std::cout << "ERROR: Test failed in testCtAttributes() for shift = " << shift << " on getNumLevels()" << std::endl; passed = false; } for (int i=0; i f, const int dimension, const int depth, const double freq, const double phase_shift, const double shift, const double exact_integral, const bool symmetric_weights, const double tolerance = 1e-10, const int use_lambda = true) { // Initialize. bool passed = true; auto sinc = [freq, phase_shift](double x)->double {return (fabs(freq * (x - phase_shift)) <= 1e-20) ? 1.0 : sin(freq * (x - phase_shift)) / (freq * (x - phase_shift));}; int level = depth % 2 == 1 ? (depth + 1) / 2 : depth / 2 + 1; TasGrid::CustomTabulated ct; if (use_lambda) { // Create the CustomTabulated object using the function lambda. ct = TasGrid::getExoticQuadrature(level, shift, sinc, 50 * depth + 1, "Sinc-Weighted Quadrature", symmetric_weights); } else { // Create the CustomTabulated object using a Gauss-Legendre reference grid. TasGrid::TasmanianSparseGrid ref_grid; ref_grid.makeGlobalGrid(1, 1, depth + 1, TasGrid::type_level, TasGrid::rule_gausslegendre); std::vector nodes = ref_grid.getPoints(); std::vector fvals(ref_grid.getNumNeeded()); std::transform(nodes.begin(), nodes.end(), fvals.begin(), sinc); ref_grid.loadNeededValues(fvals); ct = TasGrid::getExoticQuadrature(level, shift, ref_grid, "Sinc-Weighted Quadrature", symmetric_weights); } // Compute the integral and compare to the reference value for each type of CustomTabulated object. TasGrid::TasmanianSparseGrid sg; sg.makeGlobalGrid(dimension, 1, depth, TasGrid::type_qptotal, std::move(ct)); std::vector quad_points = sg.getPoints(); std::vector quad_weights = sg.getQuadratureWeights(); assert(quad_weights.size() * dimension == quad_points.size()); double approx_integral = 0.0; for (size_t i=0; i tolerance) { std::cout << "ERROR: " << std::setprecision(16) << "Computed integral value " << approx_integral << " does not match exact integral " << exact_integral << " for test problem with inputs: \n\n" << std::left << std::setw(12) << "input_type" << " = " << (use_lambda ? "function lambda" : "TasmanianSparseGrid") << "\n" << std::setw(12) << "weight_fn" << " = " << "sinc(" << freq << "*[x-" << phase_shift << "])" << "\n" << std::setw(12) << "dimension" << " = " << dimension << "\n" << std::setw(12) << "depth" << " = " << depth << "\n" << std::setw(12) << "shift" << " = " << shift << "\n" << std::setw(12) << "symmetry" << " = " << (symmetric_weights ? "true" : "false") << "\n" << std::setw(12) << "precision" << " = " << tolerance << "\n" << std::endl; passed = false; } return passed; } // Tests for the accuracy of getExoticQuadrature() when weight_fn(x) is sinc(freq * x) and f(x) is exp(-x'*x). inline bool testAccuracy() { bool passed = true; int depth, dimension; auto f1 = [](const double* x)->double{return std::exp(-x[0]*x[0]);}; auto f2 = [](const double* x)->double{return std::exp(-x[0]*x[0]-x[1]*x[1]);}; // 1D symmetric problem instances. depth = 40; dimension = 1; passed = passed && wrapSincTest(f1, dimension, depth, 1.0, 0.0, 0.0, 1.4321357541271255, true); passed = passed && wrapSincTest(f1, dimension, depth, 1.0, 0.0, 1.0, 1.4321357541271255, true); passed = passed && wrapSincTest(f1, dimension, depth, 1.0, 0.0, 1.0, 1.4321357541271255, false); passed = passed && wrapSincTest(f1, dimension, depth, 10.0, 0.0, 1.0, 0.32099682841103033, true); passed = passed && wrapSincTest(f1, dimension, depth, 100.0, 0.0, 1.0, 0.031353648322695503, true); // 1D nonsymmetric problem instances. depth = 40; dimension = 1; passed = passed && wrapSincTest(f1, dimension, depth, 1.0, 0.5, 0.0, 1.3751962080889306, false); passed = passed && wrapSincTest(f1, dimension, depth, 1.0, 0.5, 1.0, 1.3751962080889306, false); passed = passed && wrapSincTest(f1, dimension, depth, 10.0, 0.5, 1.0, 0.24655852538340614, false); passed = passed && wrapSincTest(f1, dimension, depth, 50.0, 0.5, 1.0, 0.048558733457525547, false); // 2D symmetric problem instances. depth = 40; dimension = 2; passed = passed && wrapSincTest(f2, dimension, depth, 1.0, 0.0, 0.0, 2.051012818249270, true); passed = passed && wrapSincTest(f2, dimension, depth, 1.0, 0.0, 1.0, 2.051012818249270, true); passed = passed && wrapSincTest(f2, dimension, depth, 1.0, 0.0, 1.0, 2.051012818249270, false); passed = passed && wrapSincTest(f2, dimension, depth, 10.0, 0.0, 1.0, 0.1030389638499404, true); passed = passed && wrapSincTest(f2, dimension, depth, 100.0, 0.0, 1.0, 0.0009830512631432665, true); // 1D symmetric problem instances using a reference grid. depth = 40; dimension = 1; passed = passed && wrapSincTest(f1, dimension, depth, 10.0, 0.0, 1.0, 0.32099682841103033, true, 1e-10, false); passed = passed && wrapSincTest(f1, dimension, depth, 10.0, 0.0, 1.0, 0.32099682841103033, false, 1e-10, false); passed = passed && wrapSincTest(f1, dimension, depth, 10.0, 0.5, 1.0, 0.24655852538340614, false, 1e-10, false); return passed; } // Main wrapper inline bool testExoticQuadrature() { bool passed = true; passed = passed && testNodeAndWeightSizes(); passed = passed && testBasicAttributes(); passed = passed && testAccuracy(); return passed; } TASMANIAN-8.1/Addons/testLoadUnstructured.hpp000066400000000000000000000336661470551176200210530ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "TasmanianAddons.hpp" #include "gridtestCLICommon.hpp" /*! * \brief Returns the model values at the grid points. * * Useful for verification purposes, the unstructured grid algorithm should be equivalent to the standard loadNeededPoints() * if applied to the same data, i.e., points aligned to the grid and the corresponding model values. * * \param grid is the sparse grid that will be used to load the point. * \param model is a callable method with the same signature as the array version of loadNeededPoints() * * \returns the points (first) and model data (second) in a pair of vectors */ template std::pair, std::vector> generateExactData(TasmanianSparseGrid const &grid, CallableModel model){ int num_dimensions = grid.getNumDimensions(); int num_outputs = grid.getNumOutputs(); int num_samples = grid.getNumPoints(); auto x = grid.getPoints(); std::vector y(Utils::size_mult(grid.getNumOutputs(), grid.getNumPoints())); for(int i=0; i std::pair, std::vector> generateRandomData(TasmanianSparseGrid const &grid, CallableModel model, int num_samples){ int num_dimensions = grid.getNumDimensions(); int num_outputs = grid.getNumOutputs(); std::vector transform_a, transform_b; grid.getDomainTransform(transform_a, transform_b); std::minstd_rand park_miller(42); std::uniform_real_distribution unif(0.0, 1.0); auto x = TasDREAM::genUniformSamples(transform_a, transform_b, num_samples, [&]()->double{ return unif(park_miller); }); std::vector y(Utils::size_mult(num_outputs, num_samples)); for(int i=0; i const&x, TasmanianSparseGrid const &gA, TasmanianSparseGrid const &gB){ std::vector yA, yB; gA.evaluateBatch(x, yA); gB.evaluateBatch(x, yB); double err = 0.0; for(size_t i=0; i const &x, std::vector const &y){ if (x.size() != y.size()) return 1.E+20; double err = 0.0; for(size_t i=0; i void testExactL2(TasmanianSparseGrid &&grid, CallableModel model){ grid.setDomainTransform({-0.5, -0.5, -0.5,}, {0.7, 0.7, 0.7}); auto ref_grid = grid; auto data = generateExactData(grid, model); loadNeededPoints(model, ref_grid, 1); if (OneDimensionalMeta::isNonNested(grid.getRule())) loadUnstructuredDataL2(data.first, data.second, 1.E-3, grid); else loadUnstructuredDataL2(data.first, data.second, 0.0, grid); if ((not OneDimensionalMeta::isNonNested(grid.getRule()) and coefficientDifference(ref_grid, grid) > Maths::num_tol) or (OneDimensionalMeta::isNonNested(grid.getRule()) and evalDifference(data.first, ref_grid, grid) > 1.E-2)) { cout << "Failed exact unstructured construction\n"; cout << "Observed coefficients error: " << coefficientDifference(ref_grid, grid) << "\n"; cout << "Observed evaluate error: " << evalDifference(data.first, ref_grid, grid) << "\n"; grid.printStats(); throw std::runtime_error("test failed"); } } /*! * \brief Similar to testExactL2() but the test is done using randomly selected samples. */ template void testApproxL2(TasmanianSparseGrid &&grid, CallableModel model, int num_samples, double tolerance){ grid.setDomainTransform({-0.5, -0.5, -0.5,}, {0.7, 0.7, 0.7}); auto data = generateRandomData(grid, model, num_samples); loadUnstructuredDataL2(data.first, data.second, 1.E-8, grid); std::vector surrogate; grid.evaluateBatch(data.first, surrogate); double err = vecDifference(data.second, surrogate); if (err > tolerance){ std::cout << std::scientific; std::cout.precision(10); cout << "Failed approximate unstructured construction\n"; cout << "Observed error: " << err << " tolerance: " << tolerance << "\n"; grid.printStats(); throw std::runtime_error("test failed"); } } /*! * \brief Prepare a list of tests. */ std::vector> makeTests(TypeAcceleration acc, int gpu_id){ auto model31 = [](double const x[], double y[], int)-> void{ y[0] = std::exp(-(x[0] - 0.1) * (x[1] - 0.3) * (x[1] - 0.3) * (x[2] + 0.4)); }; auto model33 = [](double const x[], double y[], int)-> void{ y[0] = std::exp(-(x[0] - 0.1) * (x[1] - 0.3) * (x[1] - 0.3) * (x[2] + 0.4)); y[1] = std::exp(-(x[0] - 0.1) * (x[1] - 0.2) * (x[2] + 0.3)); y[2] = std::exp(-(x[0] + 0.3) * (x[1] + 0.1) * (x[2] - 0.1)); }; auto set_acc = [=](TasmanianSparseGrid &&grid)-> TasmanianSparseGrid{ grid.enableAcceleration(acc, gpu_id); return std::move(grid); }; return std::vector>{ [=](void)->void{ testExactL2(set_acc(makeGlobalGrid(3, 1, 4, type_level, rule_fejer2)), model31); }, [=](void)->void{ testExactL2(set_acc(makeGlobalGrid(3, 1, 7, type_level, rule_chebyshev)), model31); }, [=](void)->void{ testExactL2(set_acc(makeSequenceGrid(3, 1, 12, type_ipcurved, rule_mindelta)), model31); }, [=](void)->void{ testExactL2(set_acc(makeLocalPolynomialGrid(3, 1, 5, 2)), model31); }, [=](void)->void{ testExactL2(set_acc(makeWaveletGrid(3, 1, 3, 1)), model31); }, [=](void)->void{ testExactL2(set_acc(makeFourierGrid(3, 1, 6, type_iphyperbolic)), model31); }, [=](void)->void{ testExactL2(set_acc(makeGlobalGrid(3, 3, 6, type_level, rule_rlejaodd)), model33); }, [=](void)->void{ testExactL2(set_acc(makeGlobalGrid(3, 3, 7, type_level, rule_chebyshev)), model33); }, [=](void)->void{ testExactL2(set_acc(makeSequenceGrid(3, 3, 6, type_ipcurved, rule_rlejashifted)), model33); }, [=](void)->void{ testExactL2(set_acc(makeLocalPolynomialGrid(3, 3, 4, 3)), model33); }, [=](void)->void{ testExactL2(set_acc(makeWaveletGrid(3, 3, 1, 3)), model33); }, [=](void)->void{ testExactL2(set_acc(makeFourierGrid(3, 3, 7, type_iphyperbolic)), model33); }, [=](void)->void{ testApproxL2(set_acc(makeGlobalGrid(3, 3, 5, type_iptotal, rule_fejer2)), model33, 200, 1.E-4); }, [=](void)->void{ testApproxL2(set_acc(makeSequenceGrid(3, 3, 6, type_ipcurved, rule_rlejashifted)), model33, 100, 1.E-4); }, [=](void)->void{ testApproxL2(set_acc(makeLocalPolynomialGrid(3, 1, 3, 2, rule_semilocalp)), model31, 120, 1.E-3); }, }; } /*! * \brief Execute the tests and returns the result. */ bool runTests(TypeAcceleration acc, bool verbose, int gpu_id){ bool pass = true; auto tests = makeTests(acc, gpu_id); int count = 1; for(auto &t : tests){ try{ t(); // run the test }catch(std::runtime_error &){ pass = false; } // this one shows which test has failed (for debugging purposes) if (verbose) std::cout << " done test: " << std::setw(2) << count++ << "/" << tests.size() << std::endl; } return pass; } /*! * \brief All tests for the loadUnstructuredDataL2() method for all acceleration modes. */ bool testLoadUnstructuredL2(bool verbose, int gpu_id){ #ifdef Tasmanian_ENABLE_DPCPP test_queue.init_testing(gpu_id); #endif bool pass = true; bool blas_pass = (AccelerationMeta::isAvailable(accel_cpu_blas)) ? runTests(accel_cpu_blas, verbose, 0) : true; if (blas_pass){ if (verbose) cout << std::setw(10) << "blas " << std::setw(30) << "unstructured construction" << std::setw(10) << "Pass" << endl; }else{ cout << "Failed testLoadUnstructuredL2() blas case.\n"; } pass = pass and blas_pass; if (AccelerationMeta::isAvailable(accel_gpu_cuda)){ int gpu_begin = (gpu_id == -1) ? 0 : gpu_id; int gpu_end = (gpu_id == -1) ? TasmanianSparseGrid::getNumGPUs() : gpu_id + 1; for(int gpu = gpu_begin; gpu < gpu_end; gpu++){ bool cublas_pass = runTests(accel_gpu_cublas, verbose, gpu); if (cublas_pass){ if (verbose) cout << std::setw(7) << "cublas" << std::setw(3) << gpu << std::setw(30) << "unstructured construction" << std::setw(10) << "Pass" << endl; }else{ cout << "Failed testLoadUnstructuredL2() cublas case on device " << gpu << "\n"; } bool cuda_pass = runTests(accel_gpu_cuda, verbose, gpu); if (cuda_pass){ if (verbose) cout << std::setw(7) << "cuda" << std::setw(3) << gpu << std::setw(30) << "unstructured construction" << std::setw(10) << "Pass" << endl; }else{ cout << "Failed testLoadUnstructuredL2() cuda case on device " << gpu << "\n"; } pass = pass and cuda_pass; if (AccelerationMeta::isAvailable(accel_gpu_magma)){ bool magma_pass = runTests(accel_gpu_magma, verbose, gpu); if (magma_pass){ if (verbose) cout << std::setw(7) << "magma" << std::setw(3) << gpu << std::setw(30) << "unstructured construction" << std::setw(10) << "Pass" << endl; }else{ cout << "Failed testLoadUnstructuredL2() magma case on device " << gpu << "\n"; } pass = pass and magma_pass; } } } if (verbose and not AccelerationMeta::isAvailable(accel_cpu_blas) and not AccelerationMeta::isAvailable(accel_gpu_cuda)) cout << "testLoadUnstructuredL2() requires BLAS or CUDA\n"; return pass; } TASMANIAN-8.1/Addons/testMPI.cpp000066400000000000000000000132121470551176200161450ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "testMPI.hpp" #include "testMPIDream.hpp" using std::cout; using std::setw; int main(int argc, char ** argv){ //MPI_Init(&argc, &argv); // MPI_THREAD_MULTIPLE requires MPI_Init_thread() int threads_available; MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &threads_available); int me = TasGrid::getMPIRank(MPI_COMM_WORLD); if (me == 0) cout << "\n"; // --------------- Send/Recv ----------------- // if (!testSendReceive()) throw std::runtime_error("failed Send/Recv ascii"); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Send/Recv Pass\n"; // --------------- Send/Recv ----------------- // if (!testSendReceive()) throw std::runtime_error("failed Send/Recv binary"); MPI_Barrier(MPI_COMM_WORLD); if (!testLikelySendRecv()) throw std::runtime_error("failed Send/Recv DREAM"); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Send/Recv Pass\n"; // ----------------- Bcast ------------------ // if (!testBcast()) throw std::runtime_error("failed Bcast ascii"); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Bcast Pass\n"; // ----------------- Bcast ----------------- // if (!testBcast()) throw std::runtime_error("failed Bcast binary"); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Bcast Pass\n"; // ----------------- Scatter --------------- // if (!testScatterOutputs()) throw std::runtime_error("failed Scatter ascii"); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Scatter Pass\n"; // ----------------- Scatter --------------- // if (!testScatterOutputs()) throw std::runtime_error("failed Scatter binary"); MPI_Barrier(MPI_COMM_WORLD); if (!testLikelyScatter()) throw std::runtime_error("failed Scatter DREAM"); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Scatter Pass\n"; if (threads_available == MPI_THREAD_MULTIPLE){ // ----------------- Construct ----------- // testMPIconstruct(); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Construct Pass\n"; // ----------------- Construct --------- // testMPIconstruct(); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Construct Pass\n"; // ----------------- Construct --------- // testMPIconstructStrict(); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Construct Pass\n"; }else{ if (me == 0) cout << "\n Skipping MPI construction since this version of MPI\n does not seem to support MPI_THREAD_MULTIPLE\n\n"; } testMPIDream(); MPI_Barrier(MPI_COMM_WORLD); if (me == 0) cout << " MPI Dream Pass\n"; // --------------- Finalize ------------------------- // MPI_Finalize(); if (me == 0) cout << endl; return 0; } TASMANIAN-8.1/Addons/testMPI.hpp000066400000000000000000000313221470551176200161540ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "TasmanianAddons.hpp" #include "gridtestCLICommon.hpp" /*! * \brief Check if the points in the two grids match bit-wise. */ inline bool checkPoints(TasGrid::TasmanianSparseGrid const &gridA, TasGrid::TasmanianSparseGrid const &gridB){ if (gridA.getNumPoints() != gridB.getNumPoints()) return false; if (gridA.getNumDimensions() != gridB.getNumDimensions()) return false; auto pA = gridA.getPoints(); auto pB = gridB.getPoints(); double err = 0.0; for(auto x = pA.begin(), y = pB.begin(); x != pA.end(); x++, y++) err += std::abs(*x - *y); return (err == 0.0); // bit-wise match is reasonable to expect here, but use with caution for some grids } /*! * \brief Simple test of MPI Send/Recv of sparse grids, binary and ascii formats. */ template bool testSendReceive(){ MPI_Comm comm = MPI_COMM_WORLD; auto true_grid = TasGrid::makeGlobalGrid(5, 3, 4, TasGrid::type_level, TasGrid::rule_clenshawcurtis); int tag = 1; int const me = TasGrid::getMPIRank(comm); if (me == 0){ return (TasGrid::MPIGridSend(true_grid, 1, tag, comm) == MPI_SUCCESS); }else if (me == 1){ MPI_Status status; TasGrid::TasmanianSparseGrid grid; auto result = TasGrid::MPIGridRecv(grid, 0, tag, comm, &status); if (result != MPI_SUCCESS) return false; return checkPoints(true_grid, grid); }else{ return true; } } /*! * \brief Simple test of MPI Send/Recv of sparse grids, binary and ascii formats. */ template bool testBcast(){ MPI_Comm comm = MPI_COMM_WORLD; auto true_grid = TasGrid::makeGlobalGrid(5, 1, 4, TasGrid::type_level, TasGrid::rule_clenshawcurtis); int const me = TasGrid::getMPIRank(comm); if (me == 1){ // using proc 1 to Bcast the grid return (TasGrid::MPIGridBcast(true_grid, 1, comm) == MPI_SUCCESS); }else{ TasGrid::TasmanianSparseGrid grid; auto result = TasGrid::MPIGridBcast(grid, 1, comm); if (result != MPI_SUCCESS) return false; return checkPoints(true_grid, grid); } } /*! * \brief Simple test of MPI Scatter Outputs of sparse grids, binary and ascii formats. */ template bool testScatterOutputs(){ // grid has 7 outputs split between 3 ranks gives (3 2 2) MPI_Comm comm = MPI_COMM_WORLD; int const me = TasGrid::getMPIRank(comm); auto reference_grid = TasGrid::makeGlobalGrid(3, (me == 0) ? 3 : 2, 4, TasGrid::type_level, TasGrid::rule_clenshawcurtis); loadNeededPoints([&](double const x[], double y[], size_t)->void{ double expval = std::exp(x[0] + x[1] + x[2]); // 3 inputs if (me == 0){ y[0] = expval; y[1] = 2.0 * expval; y[2] = 3.0 * expval; }else if (me == 1){ y[0] = 4.0 * expval; y[1] = 5.0 * expval; }else{ y[0] = 6.0 * expval; y[1] = 7.0 * expval; } }, reference_grid, 0); TasmanianSparseGrid grid; // received grid // use rank 1 for the root if (me == 1){ auto full_grid = TasGrid::makeGlobalGrid(3, 7, 4, TasGrid::type_level, TasGrid::rule_clenshawcurtis); loadNeededPoints([&](double const x[], double y[], size_t)->void{ double expval = std::exp(x[0] + x[1] + x[2]); // 3 inputs for(size_t i=0; i<7; i++) y[i] = double(i+1) * expval; }, full_grid, 0); MPIGridScatterOutputs(full_grid, grid, 1, 2, comm); }else{ MPIGridScatterOutputs(TasmanianSparseGrid(), grid, 1, 2, comm); } std::minstd_rand park_miller(99); std::uniform_real_distribution unif(-1.0, 1.0); std::vector test_points(3 * 1000); for(auto &t : test_points) t = unif(park_miller); auto match = [&](TasmanianSparseGrid const &a, TasmanianSparseGrid const &b)->bool{ std::vector resa, resb; // reference and actual result a.evaluateBatch(test_points, resa); b.evaluateBatch(test_points, resb); double err = 0.0; for(auto ia = resa.begin(), ib = resb.begin(); ia != resa.end(); ia++, ib++) err = std::max(err, std::abs(*ia - *ib)); return (err < 1.E-13); }; if (!match(grid, reference_grid)) throw std::runtime_error("ERROR: first iteration of MPIGridScatterOutputs() failed."); MPIGridScatterOutputs(copyGrid(grid), grid, 1, 2, comm); if (me == 2){ if (!grid.empty()) throw std::runtime_error("ERROR: second iteration of MPIGridScatterOutputs() failed."); }else{ reference_grid = TasGrid::makeGlobalGrid(3, 1, 4, TasGrid::type_level, TasGrid::rule_clenshawcurtis); loadNeededPoints([&](double const x[], double y[], size_t)->void{ double expval = std::exp(x[0] + x[1] + x[2]); // 3 inputs y[0] = ((me == 0) ? 4.0 : 5.0) * expval; }, reference_grid, 0); if (!match(grid, reference_grid)) throw std::runtime_error("ERROR: second iteration of MPIGridScatterOutputs() failed."); } MPIGridScatterOutputs(copyGrid(grid), grid, 1, 2, comm); if (me == 0){ reference_grid = TasGrid::makeGlobalGrid(3, 1, 4, TasGrid::type_level, TasGrid::rule_clenshawcurtis); loadNeededPoints([&](double const x[], double y[], size_t)->void{ y[0] = 5.0 * std::exp(x[0] + x[1] + x[2]); }, reference_grid, 0); if (!match(grid, reference_grid)) throw std::runtime_error("ERROR: third iteration of MPIGridScatterOutputs() failed."); }else{ if (!grid.empty()) throw std::runtime_error("ERROR: third iteration of MPIGridScatterOutputs() failed."); } return true; } template void testMPIconstruct(){ MPI_Comm comm = MPI_COMM_WORLD; int const me = TasGrid::getMPIRank(comm); std::minstd_rand park_miller(99); std::uniform_real_distribution unif(-1.0, 1.0); std::vector test_points(3 * 1000); for(auto &t : test_points) t = unif(park_miller); auto match = [&](TasmanianSparseGrid const &a, TasmanianSparseGrid const &b)->bool{ std::vector resa, resb; // reference and actual result a.evaluateBatch(test_points, resa); b.evaluateBatch(test_points, resb); double err = 0.0; for(auto ia = resa.begin(), ib = resb.begin(); ia != resa.end(); ia++, ib++) err = std::max(err, std::abs(*ia - *ib)); constexpr double tolerance = 2.E-2; if (err >= tolerance) std::cout << "error = " << err << " expected " << tolerance << std::endl; return (err < tolerance); }; auto model = [&](std::vector const &x, std::vector &y)->void{ size_t num_samples = x.size() / 3; if (use_initial_guess == with_initial_guess) y.resize(num_samples * 2); // y can be empty for(size_t i=0; i const &x, std::vector &y, size_t)->void{ model(x, y); }; auto grid = TasGrid::makeLocalPolynomialGrid(3, 2, 3); if (me == 0){ mpiConstructSurrogate(model, 3, 2, 1000, 2, 3, 11, 22, 0, comm, grid, 1.E-5, refine_classic, -1); }else{ mpiConstructWorker(model, 3, 2, 2, 3, 11, 22, 0, comm); } if (me == 0){ auto reference_grid = TasGrid::makeLocalPolynomialGrid(3, 2, 3); constructSurrogate(modelt, 1000, 0, 1, reference_grid, 1.E-5, refine_classic, -1); if (!match(grid, reference_grid)) throw std::runtime_error("testMPIconstruct() grids mismatch."); } } // this test must produce grids that match to within numeric precision // no matter the order of samples or any other considerations void testMPIconstructStrict(){ MPI_Comm comm = MPI_COMM_WORLD; int const me = TasGrid::getMPIRank(comm); auto match = [](TasmanianSparseGrid const &a, TasmanianSparseGrid const &b)->bool{ if (a.getNumLoaded() != b.getNumLoaded()) return false; auto pa = a.getLoadedPoints(); auto pb = b.getLoadedPoints(); double err = 0.0; for(auto ia = pa.begin(), ib = pb.begin(); ia != pa.end(); ia++, ib++) err = std::max(err, std::abs(*ia - *ib)); if (err >= Maths::num_tol) cout << "points mismatch: " << err << endl; return (err < Maths::num_tol); }; auto modelt = [&](std::vector const &x, std::vector &y, size_t)->void{ size_t num_samples = x.size() / 2; for(size_t i=0; i const &x, std::vector &y)->void{ modelt(x, y, 0); if (me == 0) throw std::runtime_error("ERROR: rank 0 should not participate in this."); //std::this_thread::sleep_for(std::chrono::milliseconds(1100)); }; std::vector aweights = {1, 2}; auto reference_grid = TasGrid::makeSequenceGrid(2, 1, 6, TasGrid::type_level, TasGrid::rule_leja, aweights); auto grid = copyGrid(reference_grid); loadNeededPoints(modelt, reference_grid, 0); mpiConstructSurrogate (model, 2, 1, reference_grid.getNumLoaded(), 1, 2, 11, 22, 0, comm, grid, TasGrid::type_iptotal, aweights); if (me == 0){ if (!match(grid, reference_grid)) throw std::runtime_error("ERROR: CV construction failed."); } } TASMANIAN-8.1/Addons/testMPIDream.hpp000066400000000000000000000215341470551176200171310ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "TasmanianAddons.hpp" #include "gridtestCLICommon.hpp" inline bool testLikelySendRecv(){ int me = TasGrid::getMPIRank(MPI_COMM_WORLD); TasDREAM::LikelihoodGaussIsotropic ref_isolike(10.0, {1.0, 2.0, 3.0}); if (me == 0){ if (TasDREAM::MPILikelihoodSend(ref_isolike, 1, 11, MPI_COMM_WORLD) != MPI_SUCCESS) return false; }else if (me == 1){ TasDREAM::LikelihoodGaussIsotropic isolike; if (TasDREAM::MPILikelihoodRecv(isolike, 0, 11, MPI_COMM_WORLD) != MPI_SUCCESS) return false; std::vector model = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; // full rank matrix to cover all entries std::vector result(3), true_result(3); isolike.getLikelihood(TasDREAM::logform, model, result); ref_isolike.getLikelihood(TasDREAM::logform, model, true_result); for(size_t i=0; i<3; i++) if (std::abs(result[i] - true_result[i]) > TasGrid::Maths::num_tol) return false; } TasDREAM::LikelihoodGaussAnisotropic ref_alike({4.0, 5.0, 6.0}, {1.0, 2.0, 3.0}); if (me == 1){ if (TasDREAM::MPILikelihoodSend(ref_alike, 2, 12, MPI_COMM_WORLD) != MPI_SUCCESS) return false; }else if (me == 2){ TasDREAM::LikelihoodGaussAnisotropic alike; if (TasDREAM::MPILikelihoodRecv(alike, 1, 12, MPI_COMM_WORLD) != MPI_SUCCESS) return false; std::vector model = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; // full rank matrix to cover all entries std::vector result(3), true_result(3); alike.getLikelihood(TasDREAM::logform, model, result); ref_alike.getLikelihood(TasDREAM::logform, model, true_result); for(size_t i=0; i<3; i++) if (std::abs(result[i] - true_result[i]) > TasGrid::Maths::num_tol) return false; } return true; } inline bool testLikelyScatter(){ int me = TasGrid::getMPIRank(MPI_COMM_WORLD); int tag = 11; TasDREAM::LikelihoodGaussIsotropic source(10.0, {1.0, 2.0, 3.0}); TasDREAM::LikelihoodGaussIsotropic reference; TasDREAM::LikelihoodGaussIsotropic destination; if (me == 0){ reference.setData(10.0, {1.0}); MPILikelihoodScatter(source, destination, 0, tag, MPI_COMM_WORLD); }else if (me == 1){ reference.setData(10.0, {2.0}); MPILikelihoodScatter(TasDREAM::LikelihoodGaussIsotropic(), destination, 0, tag, MPI_COMM_WORLD); }else{ reference.setData(10.0, {3.0}); MPILikelihoodScatter(TasDREAM::LikelihoodGaussIsotropic(), destination, 0, tag, MPI_COMM_WORLD); } std::vector model = {1.0}; // full rank matrix to cover all entries std::vector result(1), true_result(1); destination.getLikelihood(TasDREAM::logform, model, result); reference.getLikelihood(TasDREAM::logform, model, true_result); if (std::abs(result[0] - true_result[0]) > TasGrid::Maths::num_tol) return false; TasDREAM::LikelihoodGaussAnisotropic asource({14.0, 15.0}, {1.0, 2.0}); TasDREAM::LikelihoodGaussAnisotropic areference; TasDREAM::LikelihoodGaussAnisotropic adestination; if (me == 0){ areference.setData({14.0}, {1.0}); MPILikelihoodScatter(asource, adestination, 0, tag, MPI_COMM_WORLD); }else if (me == 1){ areference.setData({15.0}, {2.0}); MPILikelihoodScatter(TasDREAM::LikelihoodGaussAnisotropic(), adestination, 0, tag, MPI_COMM_WORLD); }else{ MPILikelihoodScatter(TasDREAM::LikelihoodGaussAnisotropic(), adestination, 0, tag, MPI_COMM_WORLD); } if (me != 2){ result = {0.0}; true_result = {11.0}; adestination.getLikelihood(TasDREAM::logform, model, result); areference.getLikelihood(TasDREAM::logform, model, true_result); if (std::abs(result[0] - true_result[0]) > TasGrid::Maths::num_tol) return false; }else{ if (adestination.getNumOutputs() != 0){ std::cout << "last rank did not receive empty likelihood." << std::endl; return false; } } return true; } void testMPIDream(){ int num_chains = 10; int me = TasGrid::getMPIRank(MPI_COMM_WORLD); auto full_grid = TasGrid::makeSequenceGrid(2, 7, 2, TasGrid::type_level, TasGrid::rule_rleja); TasGrid::loadNeededPoints([&](std::vector const &x, std::vector &y, size_t)->void{ y = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; for(size_t i=0; i unif(0.0, 1.0); std::vector initial_state; TasDREAM::genGaussianSamples({0.0, 0.0}, {0.2, 0.2}, num_chains, initial_state, [&]()->double{ return unif(park_miller_init); }); if (me == 0) state.setState(initial_state); full_state.setState(initial_state); TasDREAM::SampleDREAM(10, 10, TasDREAM::DistributedPosterior(grid, likely, TasDREAM::uniform_prior, 2, num_chains, 0, MPI_COMM_WORLD), grid.getDomainInside(), state, TasDREAM::dist_uniform, 0.05, TasDREAM::const_percent<50>, [&]()->double{ return unif(park_miller1); } ); TasDREAM::SampleDREAM(10, 10, TasDREAM::posterior(full_grid, full_likelihood, TasDREAM::uniform_prior), grid.getDomainInside(), full_state, TasDREAM::dist_uniform, 0.05, TasDREAM::const_percent<50>, [&]()->double{ return unif(park_miller2); } ); if (me == 0){ std::vector mean, variance; state.getHistoryMeanVariance(mean, variance); std::vector ref_mean, ref_variance; full_state.getHistoryMeanVariance(ref_mean, ref_variance); if (((std::abs(mean[0] - ref_mean[0]) + std::abs(mean[1] - ref_mean[1])) > 1.E-9) || ((std::abs(variance[0] - ref_variance[0]) + std::abs(variance[1] - ref_variance[1])) > 1.E-9)) throw std::runtime_error("ERROR: mismatch in sampling between reference and computed DREAM."); } } TASMANIAN-8.1/Addons/tsgAddonsCommon.hpp000066400000000000000000000057651470551176200177420ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_COMMON_HPP #define __TASMANIAN_ADDONS_COMMON_HPP /*! * \internal * \file tsgAddonsCommon.hpp * \brief Common includes and methods for all addons. * \author Miroslav Stoyanov * \ingroup TasmanianAddonsCommon * * All addon templates will include this core file. * \endinternal */ #include #include #include #include #include #include #include "TasmanianOptimization.hpp" #ifdef Tasmanian_ENABLE_MPI #include "mpi.h" #endif /*! * \internal * \ingroup TasmanianAddons * \addtogroup TasmanianAddonsCommon Addons Common * * Common Methods for the Addons Module. * \endinternal */ #endif TASMANIAN-8.1/Addons/tsgCConstructSurrogate.cpp000066400000000000000000000362231470551176200213300ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_CCONSTRUCTSURROGATE_CPP #define __TASMANIAN_ADDONS_CCONSTRUCTSURROGATE_CPP #include "TasmanianAddons.hpp" extern "C"{ // num_samples, num_dimensions, x.data(), num_outputs, y.data(), thread_id, error_code using tsg_scs_model = void (*)(int, int, double const*, int, double*, int, int*); void tsgConstructSurrogateNoIGSurplus (tsg_scs_model pymodel, int max_num_points, int num_parallel_jobs, int max_samples_per_job, void *grid_pntr, double tolerance, const char* s_criteria, int output, int *llimits, const char *checkpoint_filename, int *err){ *err = 1; TasGrid::TasmanianSparseGrid &grid = *reinterpret_cast(grid_pntr); int const num_dimensions = grid.getNumDimensions(); int const num_outputs = grid.getNumOutputs(); TasGrid::TypeRefinement criteria = TasGrid::IO::getTypeRefinementString(s_criteria); std::vector level_limits = TasGrid::Utils::copyArray(llimits, num_dimensions); std::string cfname = (checkpoint_filename != nullptr) ? std::string(checkpoint_filename) : std::string(); auto cpp_model = [&](std::vector const &x, std::vector &y, size_t thread_id)-> void{ int sample_size = (int) x.size() / num_dimensions; int error_code = 0; pymodel(sample_size, num_dimensions, x.data(), num_outputs, y.data(), (int) thread_id, &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgConstructSurrogateNoIGSurplus()"); }; try{ if (num_parallel_jobs > 1){ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, tolerance, criteria, output, level_limits, cfname); }else{ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, tolerance, criteria, output, level_limits, cfname); } *err = 0; // success }catch(std::runtime_error &){} // *err will remain 1 } void tsgConstructSurrogateNoIGAniso (tsg_scs_model pymodel, int max_num_points, int num_parallel_jobs, int max_samples_per_job, void *grid_pntr, const char* s_type, int output, int *llimits, const char *checkpoint_filename, int *err){ *err = 1; TasGrid::TasmanianSparseGrid &grid = *reinterpret_cast(grid_pntr); int const num_dimensions = grid.getNumDimensions(); int const num_outputs = grid.getNumOutputs(); TasGrid::TypeDepth dtype = TasGrid::IO::getDepthTypeString(s_type); std::vector level_limits = TasGrid::Utils::copyArray(llimits, num_dimensions); std::string cfname = (checkpoint_filename != nullptr) ? std::string(checkpoint_filename) : std::string(); auto cpp_model = [&](std::vector const &x, std::vector &y, size_t thread_id)-> void{ int sample_size = (int) x.size() / num_dimensions; int error_code = 0; pymodel(sample_size, num_dimensions, x.data(), num_outputs, y.data(), (int) thread_id, &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgConstructSurrogateNoIGAniso()"); }; try{ if (num_parallel_jobs > 1){ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, dtype, output, level_limits, cfname); }else{ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, dtype, output, level_limits, cfname); } *err = 0; // success }catch(std::runtime_error &){} // *err will remain 1 } void tsgConstructSurrogateNoIGAnisoFixed (tsg_scs_model pymodel, int max_num_points, int num_parallel_jobs, int max_samples_per_job, void *grid_pntr, const char* s_type, int *aweights, int *llimits, const char *checkpoint_filename, int *err){ *err = 1; TasGrid::TasmanianSparseGrid &grid = *reinterpret_cast(grid_pntr); int const num_dimensions = grid.getNumDimensions(); int const num_outputs = grid.getNumOutputs(); TasGrid::TypeDepth dtype = TasGrid::IO::getDepthTypeString(s_type); std::vector anisotropic_weights = TasGrid::Utils::copyArray(aweights, num_dimensions * ((TasGrid::OneDimensionalMeta::isTypeCurved(dtype)) ? 2 : 1)); std::vector level_limits = TasGrid::Utils::copyArray(llimits, num_dimensions); std::string cfname = (checkpoint_filename != nullptr) ? std::string(checkpoint_filename) : std::string(); auto cpp_model = [&](std::vector const &x, std::vector &y, size_t thread_id)-> void{ int sample_size = (int) x.size() / num_dimensions; int error_code = 0; pymodel(sample_size, num_dimensions, x.data(), num_outputs, y.data(), (int) thread_id, &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgConstructSurrogateNoIGAnisoFixed()"); }; try{ if (num_parallel_jobs > 1){ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, dtype, anisotropic_weights, level_limits, cfname); }else{ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, dtype, anisotropic_weights, level_limits, cfname); } *err = 0; // success }catch(std::runtime_error &){} // *err will remain 1 } // num_samples, num_dimensions, x.data(), has_init_guess, num_outputs, y.data(), thread_id, error_code using tsg_ics_model = void (*)(int, int, double const*, int, int, double*, int, int*); void tsgConstructSurrogateWiIGSurplus (tsg_ics_model pymodel, int max_num_points, int num_parallel_jobs, int max_samples_per_job, void *grid_pntr, double tolerance, const char* s_criteria, int output, int *llimits, const char *checkpoint_filename, int *err){ *err = 1; TasGrid::TasmanianSparseGrid &grid = *reinterpret_cast(grid_pntr); int const num_dimensions = grid.getNumDimensions(); int const num_outputs = grid.getNumOutputs(); TasGrid::TypeRefinement criteria = TasGrid::IO::getTypeRefinementString(s_criteria); std::vector level_limits = TasGrid::Utils::copyArray(llimits, num_dimensions); std::string cfname = (checkpoint_filename != nullptr) ? std::string(checkpoint_filename) : std::string(); auto cpp_model = [&](std::vector const &x, std::vector &y, size_t thread_id)-> void{ int sample_size = (int) x.size() / num_dimensions; int ihas_guess = 1; // assume there is a guess if (y.empty()){ ihas_guess = 0; // no guess y.resize(TasGrid::Utils::size_mult(sample_size, num_outputs)); } int error_code = 0; pymodel(sample_size, num_dimensions, x.data(), ihas_guess, num_outputs, y.data(), (int) thread_id, &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgConstructSurrogateWiIGSurplus()"); }; try{ if (num_parallel_jobs > 1){ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, tolerance, criteria, output, level_limits, cfname); }else{ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, tolerance, criteria, output, level_limits, cfname); } *err = 0; // success }catch(std::runtime_error &){} // *err will remain 1 } void tsgConstructSurrogateWiIGAniso (tsg_ics_model pymodel, int max_num_points, int num_parallel_jobs, int max_samples_per_job, void *grid_pntr, const char* s_type, int output, int *llimits, const char *checkpoint_filename, int *err){ *err = 1; TasGrid::TasmanianSparseGrid &grid = *reinterpret_cast(grid_pntr); int const num_dimensions = grid.getNumDimensions(); int const num_outputs = grid.getNumOutputs(); TasGrid::TypeDepth dtype = TasGrid::IO::getDepthTypeString(s_type); std::vector level_limits = TasGrid::Utils::copyArray(llimits, num_dimensions); std::string cfname = (checkpoint_filename != nullptr) ? std::string(checkpoint_filename) : std::string(); auto cpp_model = [&](std::vector const &x, std::vector &y, size_t thread_id)-> void{ int sample_size = (int) x.size() / num_dimensions; int ihas_guess = 1; // assume there is a guess if (y.empty()){ ihas_guess = 0; // no guess y.resize(TasGrid::Utils::size_mult(sample_size, num_outputs)); } int error_code = 0; pymodel(sample_size, num_dimensions, x.data(), ihas_guess, num_outputs, y.data(), (int) thread_id, &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgConstructSurrogateWiIGAniso()"); }; try{ if (num_parallel_jobs > 1){ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, dtype, output, level_limits, cfname); }else{ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, dtype, output, level_limits, cfname); } *err = 0; // success }catch(std::runtime_error &){} // *err will remain 1 } void tsgConstructSurrogateWiIGAnisoFixed (tsg_ics_model pymodel, int max_num_points, int num_parallel_jobs, int max_samples_per_job, void *grid_pntr, const char* s_type, int *aweights, int *llimits, const char *checkpoint_filename, int *err){ *err = 1; TasGrid::TasmanianSparseGrid &grid = *reinterpret_cast(grid_pntr); int const num_dimensions = grid.getNumDimensions(); int const num_outputs = grid.getNumOutputs(); TasGrid::TypeDepth dtype = TasGrid::IO::getDepthTypeString(s_type); std::vector anisotropic_weights = TasGrid::Utils::copyArray(aweights, num_dimensions * ((TasGrid::OneDimensionalMeta::isTypeCurved(dtype)) ? 2 : 1)); std::vector level_limits = TasGrid::Utils::copyArray(llimits, num_dimensions); std::string cfname = (checkpoint_filename != nullptr) ? std::string(checkpoint_filename) : std::string(); auto cpp_model = [&](std::vector const &x, std::vector &y, size_t thread_id)-> void{ int sample_size = (int) x.size() / num_dimensions; int ihas_guess = 1; // assume there is a guess if (y.empty()){ ihas_guess = 0; // no guess y.resize(TasGrid::Utils::size_mult(sample_size, num_outputs)); } int error_code = 0; pymodel(sample_size, num_dimensions, x.data(), ihas_guess, num_outputs, y.data(), (int) thread_id, &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgConstructSurrogateWiIGAnisoFixed()"); }; try{ if (num_parallel_jobs > 1){ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, dtype, anisotropic_weights, level_limits, cfname); }else{ TasGrid::constructSurrogate (cpp_model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, dtype, anisotropic_weights, level_limits, cfname); } *err = 0; // success }catch(std::runtime_error &){} // *err will remain 1 } } // extern "C" #endif TASMANIAN-8.1/Addons/tsgCExoticQuadrature.cpp000066400000000000000000000065451470551176200207450ustar00rootroot00000000000000/* * Copyright (c) 2021, Miroslav Stoyanov & William Kong * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND * IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE * OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL * ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES * RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING * FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_CEXOTICQUADRATURE_CPP #define __TASMANIAN_ADDONS_CEXOTICQUADRATURE_CPP #include "TasmanianAddons.hpp" using tsg_weight_fn = double(*)(double); extern "C"{ void tsgCreateExoticQuadratureFromGrid(void* custom_tabulated, const int level, const double shift, void* grid, const char* description, const bool is_symmetric) { *((TasGrid::CustomTabulated*) custom_tabulated) = TasGrid::getExoticQuadrature(level, shift, *reinterpret_cast(grid), description, is_symmetric); } void tsgCreateExoticQuadratureFromFunction(void* custom_tabulated, const int level, const double shift, tsg_weight_fn weight_fn, const int nref, const char* description, const bool is_symmetric) { *((TasGrid::CustomTabulated*) custom_tabulated) = TasGrid::getExoticQuadrature(level, shift, weight_fn, nref, description, is_symmetric); } } // extern "C" #endif TASMANIAN-8.1/Addons/tsgCLoadNeededValues.cpp000066400000000000000000000101711470551176200206060ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_CLOADNEEDEDVALS_CPP #define __TASMANIAN_ADDONS_CLOADNEEDEDVALS_CPP #include "TasmanianAddons.hpp" extern "C"{ // x.size(), x.data(), y.size(), y.data(), thread_id using tsg_lnp_model = void (*)(int, double const*, int, double*, int, int*); void tsgLoadNeededValues(int overwrite, tsg_lnp_model pymodel, void *grid_pntr, int num_threads, int *err){ *err = 1; // produce an error code, if not ended early try{ TasGrid::TasmanianSparseGrid &grid = *reinterpret_cast(grid_pntr); int const num_dimensions = grid.getNumDimensions(); int const num_outputs = grid.getNumOutputs(); auto cpp_model = [&](double const x[], double y[], size_t thread_id)-> void{ int error_code = 0; pymodel(num_dimensions, x, num_outputs, y, (int) thread_id, &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgLoadNeededValues()"); }; constexpr bool needed = true; constexpr bool loaded = false; if (num_threads > 1){ if (overwrite != 0){ TasGrid::loadNeededValues(cpp_model, grid, num_threads); }else{ TasGrid::loadNeededValues(cpp_model, grid, num_threads); } }else{ if (overwrite != 0){ TasGrid::loadNeededValues(cpp_model, grid, 1); }else{ TasGrid::loadNeededValues(cpp_model, grid, 1); } } *err = 0; // got here, no exceptions were encountered }catch(std::runtime_error &){} // keep *err set to 1 } } // extern "C" #endif TASMANIAN-8.1/Addons/tsgCLoadUnstructuredPoints.cpp000066400000000000000000000054331470551176200221530ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_CLOADUNSTRUCTURED_CPP #define __TASMANIAN_ADDONS_CLOADUNSTRUCTURED_CPP #include "TasmanianAddons.hpp" extern "C"{ void tsgLoadUnstructuredDataL2(double const data_points[], int num_data, double const model_values[], double tolerance, void *grid){ TasGrid::loadUnstructuredDataL2(data_points, num_data, model_values, tolerance, *reinterpret_cast(grid)); } } // extern "C" #endif TASMANIAN-8.1/Addons/tsgCandidateManager.hpp000066400000000000000000000267151470551176200205260ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_CMANAGER_HPP #define __TASMANIAN_ADDONS_CMANAGER_HPP /*! * \internal * \file tsgCandidateManager.hpp * \brief Manager for manipulations of candidate construction points. * \author Miroslav Stoyanov * \ingroup TasmanianAddonsCommon * * A class that manipulate candidate construction points. * \endinternal */ #include "tsgAddonsCommon.hpp" /*! * \ingroup TasmanianAddons * \addtogroup TasmanianAddonsConstruct Automated Surrogate Construction Procedure * * Templates that perform an automated surrogate construction to a model defined * by a lambda expression. * This allows for a one-click (or one function call) grid construction where * the samples can be computed either sequentially or in parallel. * The procedure is carried out until either a target accuracy is reached * or a computational budget is exhausted. */ namespace TasGrid{ /*! * \internal * \ingroup TasmanianAddonsConstruct * \brief Manages candidate points. * * Class for book keeping of candidate construction points, * e.g., started jobs, finished jobs, available jobs. * \endinternal */ class CandidateManager{ protected: //! \brief Jobs are divided into already checked-out (running), checked-in (done), and available (free). enum TypeStatus{ free, running, done }; public: //! \brief Constructor, accepts number of dimensions as a constant parameter. template CandidateManager(IntTypeDim dimensions, IntTypeBatch batch_size) : num_dimensions(static_cast(dimensions)), num_batch(batch_size), num_candidates(0), num_running(0), num_done(0){} //! \brief Default destructor. ~CandidateManager(){} /*! * \brief Assign a new set of candidate points. * * The new candidates are provided in the order of importance, * but a lexicographical sorted list will also be created for searching purposes. * The new set of points is also assumed to contain the currently running jobs. */ void operator=(std::vector &&new_candidates){ candidates = std::move(new_candidates); num_candidates = candidates.size() / num_dimensions; num_done = 0; if (num_candidates == 0) return; sort_candidates(); status.resize(num_candidates); std::fill(status.begin(), status.end(), free); for(auto const &p : running_jobs){ size_t i = find(p.data()); if (i < num_candidates) status[sorted[i]] = running; } } //! \brief Mark a point as "complete". void complete(std::vector const &p){ size_t num_complete = p.size() / num_dimensions; num_done += num_complete; num_running -= num_complete; for(auto ip = p.begin(); ip != p.end(); std::advance(ip, num_dimensions)){ auto i = find(&*ip); // there is a scenario where a point is checked out // then while computing another point is done which changes the surpluses // and then the checked out point is no longer a candidate if (i < num_candidates) status[sorted[i]] = done; } // takes an iterator and returns an iterator to the next entry auto inext = [](std::forward_list>::iterator ib)-> std::forward_list>::iterator{ return ++ib; }; for(size_t i=0; idata())) ib++; running_jobs.erase_after(ib); } } //! \brief Returns the next best point to compute, returns empty vector if no points are available. std::vector next(size_t remaining_budget){ size_t this_batch = std::min(remaining_budget, num_batch); size_t i = 0; while((i < num_candidates) && (status[i] != free)) i++; if (i == num_candidates) return std::vector(); num_running++; status[i] = running; std::vector result(&candidates[i*num_dimensions], &candidates[i*num_dimensions] + num_dimensions); running_jobs.push_front(result); size_t num_next = 1; while((i < num_candidates) && (num_next < this_batch)){ while((i < num_candidates) && (status[i] != free)) i++; if (i < num_candidates){ running_jobs.push_front(std::vector(&candidates[i*num_dimensions], &candidates[i*num_dimensions] + num_dimensions)); result.insert(result.end(), &candidates[i*num_dimensions], &candidates[i*num_dimensions] + num_dimensions); num_next++; num_running++; status[i++] = running; } } return result; } //! \brief Returns the number of running jobs. size_t getNumRunning() const{ return num_running; } //! \brief Returns the number of complete jobs. size_t getNumDone() const{ return num_done; } //! \brief Returns the number of all candidate jobs. size_t getNumCandidates() const{ return num_candidates; } protected: //! \brief Returns \b true if entries in \b a and \b b match to \b Maths::num_tol, assumes sizes match already. bool match(double const a[], double const b[]) const{ for(size_t i=0; i Maths::num_tol) return false; return true; } //! \brief Returns \b true if the lexicographical order of \b a is before \b b. bool compare(double const a[], double const b[]) const{ for(size_t i=0; i b[i] + Maths::num_tol) return false; } return false; } //! \brief Creates a sorted list of all candidates. void sort_candidates(){ sorted.resize(num_candidates); std::iota(sorted.begin(), sorted.end(), 0); std::sort(sorted.begin(), sorted.end(), [&](size_t a, size_t b)->bool{ return compare(&candidates[a*num_dimensions], &candidates[b*num_dimensions]); }); } //! \brief Find the index of the \b point within the \b canidates vector, returns \b num_candidates if not found. size_t find(double const point[]) const{ // if the point precedes the entire list, then send will craw back to -1 // if send reaches -1 in unsigned arithmetic the method will segfault int sstart = 0, send = (int) num_candidates - 1, current = (sstart + send) / 2; while (sstart <= send){ const double *cp = &candidates[sorted[current]*num_dimensions]; if (compare(cp, point)){ sstart = current + 1; }else if (compare(point, cp)){ send = current - 1; }else{ return (size_t) current; } current = (sstart + send) / 2; } return num_candidates; } private: size_t const num_dimensions, num_batch; size_t num_candidates, num_running, num_done; std::vector candidates; std::vector sorted; std::vector status; std::forward_list> running_jobs; }; /*! * \internal * \ingroup TasmanianAddonsConstruct * \brief Stores complete set of points before adding to the sparse grid. * * Constructing a grid one point at a time has high computational cost of at least O(N^2), * adding points in batches can amortize the cost to O(N log(N)). * This class stores the points temporarily before they can be loaded. * \endinternal */ class CompleteStorage{ public: //! \brief Constructor, accepts number of dimensions as a constant parameter. template CompleteStorage(IntType dimensions) : num_dimensions((size_t) dimensions){} //! \brief Default destructor. ~CompleteStorage(){} //! \brief Write the stored samples to a stream void write(std::ostream &os) const{ IO::writeNumbers(os, points.size(), values.size()); IO::writeVector(points, os); IO::writeVector(values, os); } //! \brief Read the stored samples from the stream void read(std::istream &is){ points.resize(IO::readNumber(is)); values.resize(IO::readNumber(is)); IO::readVector(is, points); IO::readVector(is, values); } //! \brief Add a point to the stored list. void add(std::vector const &x, std::vector const &y){ points.insert(points.end(), x.begin(), x.end()); values.insert(values.end(), y.begin(), y.end()); } //! \brief Move the stored points into the grid. void load(TasmanianSparseGrid &grid){ if (points.empty()) return; grid.loadConstructedPoints(points, values); points.clear(); values.clear(); } //! \brief Returns the number of stored points. size_t getNumStored() const{ return points.size() / num_dimensions; } private: size_t const num_dimensions; std::vector points, values; }; } #endif TASMANIAN-8.1/Addons/tsgConstructSurrogate.hpp000066400000000000000000000712411470551176200212310ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_CONSTRUCT_SURROGATE_HPP #define __TASMANIAN_ADDONS_CONSTRUCT_SURROGATE_HPP /*! * \internal * \file tsgConstructSurrogate.hpp * \brief Automated parallel construction procedure. * \author Miroslav Stoyanov * \ingroup TasmanianAddonsCommon * * Templates for automated surrogate construction. * \endinternal */ #include "tsgCandidateManager.hpp" namespace TasGrid{ /*! * \ingroup TasmanianAddonsConstruct * \brief Signature of a model function to be used in the construction procedures. * * This types describes an abstract model with inputs, outputs and a specific thread-id. * * \param x is the model inputs, the vector is logically organized in strips each containing a set of model inputs. * \param y is the model outputs, the vector must be logically organized in strips each containing a set of model * outputs corresponding to a set of inputs (the order must match, first set of inputs to first set outputs and so on). * In most cases, \b y will have the correct size before the call, the exception is when there is insufficient data * to compute an initial guess in a context that asks for an initial guess, then \b y will be empty and must be resized. * \param thread_id is a unique identifier of the thread associated with this model call, useful in multi-threaded context * e.g., to assign a GPU accelerator to the current call. * * The call to TasGrid::constructSurrogate() will control the maximum number of inputs in a single model call, * the total number of threads, and whether \b y will have the correct size and/or contain an initial guess. */ using ModelSignature = std::function const &x, std::vector &y, size_t thread_id)>; /*! * \ingroup TasmanianAddonsConstruct * \brief Allows for expressive calls to TasGrid::constructSurrogate(). */ constexpr bool mode_parallel = true; /*! * \ingroup TasmanianAddonsConstruct * \brief Allows for expressive calls to TasGrid::constructSurrogate(). */ constexpr bool mode_sequential = false; /*! * \ingroup TasmanianAddonsConstruct * \brief Allows for expressive calls to TasGrid::constructSurrogate(). */ constexpr bool with_initial_guess = true; /*! * \ingroup TasmanianAddonsConstruct * \brief Allows for expressive calls to TasGrid::constructSurrogate(). */ constexpr bool no_initial_guess = false; /*! * \internal * \ingroup TasmanianAddonsConstruct * \brief Construction algorithm using generic candidates procedure. * * Implements the parallel and sequential algorithms into one template that uses * the \b candidates lambda that wraps around the appropriate * TasmanianSparseGrid::getCandidateConstructionPoints() overload. * \endinternal */ template void constructCommon(ModelSignature model, size_t max_num_points, size_t num_parallel_jobs, size_t max_samples_per_job, TasmanianSparseGrid &grid, std::function(TasmanianSparseGrid &)> candidates, std::string const &checkpoint_filename){ num_parallel_jobs = std::max(size_t(1), num_parallel_jobs); max_samples_per_job = std::max(size_t(1), max_samples_per_job); size_t num_dimensions = (size_t) grid.getNumDimensions(); size_t num_outputs = (size_t) grid.getNumOutputs(); CandidateManager manager(num_dimensions, max_samples_per_job); // keeps track of started and ordered samples CompleteStorage complete(num_dimensions); // temporarily stores complete samples (batch loading is faster) std::string filename = checkpoint_filename; std::string filename_old = checkpoint_filename + "_old"; if (!filename.empty()){ // recover from an existing checkpoint std::ifstream infile(filename, std::ios::binary); try{ // attempt to recover from filename if (!infile.good()) throw std::runtime_error("missing main checkpoint"); grid.read(infile, mode_binary); complete.read(infile); }catch(std::runtime_error &){ // main file is missing or is corrupt, try the older version std::ifstream oldfile(filename_old, std::ios::binary); try{ if (!oldfile.good()) throw std::runtime_error("missing main checkpoint"); grid.read(oldfile, mode_binary); complete.read(oldfile); }catch(std::runtime_error &){ // nothing could be recovered, start over from the current grid } } } if (!filename.empty()){ // initial checkpoint std::ofstream ofs(filename, std::ios::binary); grid.write(ofs, mode_binary); // write grid to current complete.write(ofs); } // prepare several commonly used steps auto checkpoint = [&]()->void{ // keeps two saved states for the constructed grid if (!filename.empty()){ { // copy current into old and write to current std::ifstream current_state(filename, std::ios::binary); std::ofstream previous_state(filename, std::ios::binary); previous_state << current_state.rdbuf(); } std::ofstream ofs(filename, std::ios::binary); grid.write(ofs, mode_binary); // write grid to current complete.write(ofs); } }; auto load_complete = [&]()->void{ // loads any complete points, does nothing if getNumStored() is zero if (complete.getNumStored() > 0) complete.load(grid); }; auto refresh_candidates = [&]()->void{ // loads complete and asks for new candidates load_complete(); // always load before computing new candidates manager = candidates(grid); // get new candidates }; size_t total_num_launched = complete.getNumStored() + grid.getNumLoaded(); // count all launched jobs, including the ones already complete auto checkout_sample = [&]()->std::vector{ // get the "most-important" point that has not started yet auto x = manager.next(max_num_points - total_num_launched); if (x.empty()){ // did not find a job, maybe we need to refresh the candidates refresh_candidates(); x = manager.next(max_num_points - total_num_launched); // if this is empty, then we have exhausted all possible candidates } return x; }; // load the initial guess into y (is using initial guess), otherwise set y to the correct size auto set_initial_guess = [&](std::vector const &x, std::vector &y)->void{ if (use_initial_guess){ if (grid.getNumLoaded()) grid.evaluateBatch(x, y); else y.clear(); }else{ y.resize(num_outputs * (x.size() / num_dimensions)); } }; if (!grid.isUsingConstruction()) // the procedure assumes dynamic construction grid.beginConstruction(); refresh_candidates(); if (parallel_construction == mode_parallel){ // parallel version // allocate space for all x and y pairs, will be filled by workers and processed by main std::vector> x(num_parallel_jobs), y(num_parallel_jobs, std::vector(max_samples_per_job * num_outputs)); std::vector work_flag(num_parallel_jobs); constexpr int flag_done = 0; constexpr int flag_computing = 1; constexpr int flag_shutdown = 2; std::condition_variable until_someone_done; std::condition_variable until_new_job; std::mutex access_count_done; int count_done = 0; // lambda that will handle the work auto do_work = [&](size_t thread_id)->void{ int my_flag = flag_computing; while(my_flag == flag_computing){ model(x[thread_id], y[thread_id], thread_id); // does the model evaluations { // must guarantee sync between work_flag and count_done, use a lock std::lock_guard lock(access_count_done); work_flag[thread_id] = flag_done; count_done++; } until_someone_done.notify_one(); // just finished some work, notify the main thread { // wait till the main thread gives us an new piece of work std::unique_lock lock(access_count_done); until_new_job.wait(lock, [&]()->bool{ return (work_flag[thread_id] != flag_done); }); my_flag = work_flag[thread_id]; } } }; // launch initial set of jobs std::vector workers(num_parallel_jobs); for(size_t id=0; idbool{ bool any_done = false; for(size_t id=0; id 0.2)) load_complete(); // move from complete into the grid if (total_num_launched < max_num_points){ // refresh the candidates if enough of the current candidates have completed if (double(manager.getNumDone()) / double(manager.getNumCandidates()) > 0.2) refresh_candidates(); x[id] = checkout_sample(); // if necessary this will call refresh_candidates() if (!x[id].empty()){ // if empty, then we have finished all possible candidates (reached tolerance) total_num_launched += x[id].size() / num_dimensions; set_initial_guess(x[id], y[id]); work_flag[id] = flag_computing; }else{ work_flag[id] = flag_shutdown; // not enough samples, cancel the thread } }else{ work_flag[id] = flag_shutdown; // reached the budget, shutdown the thread } } } return any_done; }; while(manager.getNumRunning() > 0){ // main loop { // lock access to the count_done variable std::unique_lock lock(access_count_done); // unlock and wait until some else increments the "done" count until_someone_done.wait(lock, [&]()->bool{ return (count_done > 0); }); // the lock is back on at this point, process the completed samples, reset the count and go back to waiting count_done = 0; if (collect_finished()) checkpoint(); // if new samples were computed, save the state } // unlock the access_count_done and notify that we have loaded new jobs // without the unlock, the threads will wake up but will not be able to read the worker flags until_new_job.notify_all(); } load_complete(); // flush completed jobs for(auto &w : workers) if (w.joinable()) w.join(); // join all threads }else{ std::vector x(grid.getNumDimensions()), y( grid.getNumOutputs()); while((total_num_launched < max_num_points) && (manager.getNumCandidates() > 0)){ x = manager.next(max_num_points - total_num_launched); if (x.empty()){ // need more candidates refresh_candidates(); x = manager.next(max_num_points - total_num_launched); // if this is empty, then we have exhausted the candidates } if (!x.empty()){ // could be empty if there are no more candidates total_num_launched += x.size() / num_dimensions; set_initial_guess(x, y); model(x, y, 0); // compute a sample complete.add(x, y); manager.complete(x); // the fist thousand points can be loaded one at a time, then add when % increase of the grid is achieved if ((grid.getNumLoaded() < 1000) || (double(complete.getNumStored()) / double(grid.getNumLoaded()) > 0.2)) load_complete(); // also does checkpoint save // if done with the top % of the grid points, recompute the candidates if (double(manager.getNumDone()) / double(manager.getNumCandidates()) > 0.2) refresh_candidates(); } checkpoint(); } load_complete(); // flush completed jobs } } /*! * \ingroup TasmanianAddonsConstruct * \brief Construct a sparse grid surrogate to the model defined by the lambda. * * Creates a two way feedback between the model and the grid, samples from the model are collected * and loaded into the grid, while algorithms from the grid propose new samples according to * estimated importance. * The procedure is carried out until either tolerance is reached, the budget is exhausted, * or no more samples satisfy the level limits. * If set to parallel mode, the lambda will be called in separate threads concurrently * up to the specified maximum number. * * Two notable options are the ability to call the model with batches of samples and * the ability to assign an initial guess for each sample. * - In some cases, model evaluations can be performed much more efficiently using batches of * samples, e.g., by allowing the usage of BLAS level 3 methods (as opposed to level 2), * better occupancy on GPU accelerators, or better memory cohesion in sparse linear algebra. * For more details, see the work by:\n * E. Phipps, M. D'Elia, H. Edwards, M. Hoemmen, J. Hu, * Embedded Ensemble Propagation for Improving * Performance, Portability, and Scalability of Uncertainty Quantification on Emerging Computational Architectures, * SIAM Journal on Scientific Computing, vol. 39, num. 2, pp. C162--C193, 2017.\n * M. D'Elia, E. Phipps, A. Rushdi, M. Ebeida, * Surrogate-based Ensemble Grouping Strategies for * Embedded Sampling-based Uncertainty Quantification, arXiv:1705.02003. * * - Some models can utilize (or even require) a good initial guess to perform a simulation, * e.g., when using linear or non-linear iterative solvers. * As the sparse grid surrogate becomes closer and closer to the model, increasingly better guess can be * computes, effectively relying on the model to solve only for the correction between the current * sparse grid approximation and the actual model. For more details and examples see the work of:\n * D. Galindo, P. Jantsch, C. G. Webster, and G. Zhang, * Accelerating Stochastic Collocation Methods for Partial Differential * Equations with Random Input Data, SIAM/ASA Journal on Uncertainty Quantification, vol. 4, num. 1, pp. 1111--1137, 2016. * * The template can be instantiated in either parallel or single threaded mode, with or without an initial guess feedback, * and sampling can be performed in batches or single point. * The rest of the parameters control the computational budget and the specifics of the refinement scheme. * * \tparam parallel_construction defines the use of parallel or sequential mode. * The variable is of type \b bool but the constexpr constants * TasGrid::mode_parallel and TasGrid::mode_sequential can be used to for more * expressive calls. * \tparam initial_guess defines the state of the output vector \b y when the model is called. * If the initial guess is set to \b true (or TasGrid::with_initial_guess), * then the input will be filled with the best guess for \b y based on the current grid, * i.e., the previously computed samples. * This mode is useful when the model can benefit from a good initial guess, * e.g., when using an iterative solver. * If the model cannot use an initial guess, then use \b false * or TasGrid::no_initial_guess to avoid extraneous calls to \b grid.evaluateBatch(). * * * \param model defines the input-output relation to be approximated by the surrogate. * - Entering each call, \b x will have size equal to an even multiple of the dimension of * the gird and will hold the required sample inputs for a set of points; * the number of points is controlled by \b max_samples_per_job. * - Exiting the call, \b y must have size equal to the number of samples time * the number of outputs and must be loaded the outputs corresponding to \b x. * If running with \b initial_guess, on entry, \b y will be either loaded with * the best guess based on the previously computed samples or empty which * will indicate that there are not enough samples to make even a coarse grid. * If running without \b initial_guess, the vector will always have the correct * size, but the values will be unspecified and should be overwritten. * - If using the parallel mode, \b thread_id will be a number between 0 and * \b max_num_samples \b -1, all threads running simultaneously will be * given a different thread id. * \param max_num_points defines the computational budget for the surrogate construction. * The construction procedure will terminate after the grid has reached * the maximum number of points. * \param num_parallel_jobs defined the maximum number of concurent thread * executing different calls to the \b model. * In sequential mode, i.e., when \b parallel_construction is \b false, * this number will loosely control the frequency of recalculating * the list of candidate "most important" samples. * If set to 0, it will be used as if set to 1. * \param max_samples_per_job defines the largest number of samples per call to \b model. * In some cases, outputs can be more efficiently computed when the samples are * lumped together. If the model evaluations are not oprimized for batching * then this can be simply set to one. * If set to 0, it will be used as if set to 1. * \param grid is the resulting surrogate model. * The grid must be initialized with the appropriate type, number of dimensions, * number of outputs, and sufficiently large number of initial points * (e.g., there are enough candidates to load all threads). * This template works with local polynomial grids. * \param tolerance defines the target tolerance, identical to * TasmanianSparseGrid::setSurplusRefinement(). * \param criteria defines the refinement algorithm, identical to * TasmanianSparseGrid::setSurplusRefinement(). * \param output defines the output to use in the algorithm, identical to * TasmanianSparseGrid::setSurplusRefinement(). * \param level_limits defines the maximum level to use in each direction, * identical to TasmanianSparseGrid::setSurplusRefinement(). * If level limits are already set in the construction and/or refinement * those weights will be used, this parameter can overwrite them. * \param checkpoint_filename defines the two filenames to be used in to store the * intermediate constructed grids so that the procedure can be restarted * in case of a system crash. * If the filename is "foo" then the files will be called "foo" and "foo_old". * No intermediate saves will be made if the string is empty. * If the string is not empty, the procedure will first attempt to recover * from "foo" and "foo_old". * * \b WARNING: if the checkpoint files contain data from an older runs, the files must be deleted * to avoid recovering from the old executing. * * \throws std::runtime_error if called for a grid that is not local polynomial. * * \par Example * Constructing a surrogate to a simple exponential function with budget of 100 points * and running on 4 threads with one sample per thread: * \code * auto grid = TasGrid::makeLocalPolynomialGrid(2, ..); // sync the dimensions with number of model inputs * TasGrid::constructSurrogate([&](std::vector const &x, std::vector &y) * ->void{ y[0] = std::exp(x[0] + x[1]); }, * 100, 4, 1, grid, 1.E-6, TasGrid::refine_classic); * \endcode * The procedure will terminate after 100 samples or after the tolerance of 1.E-6 has been reached. * * \par Checkpoint Restart * Large scale simulations that take long time to complete, run a significant risk of * system failure which can waste significant computing resources. * Checkpoint-restart is a technique to periodically save the computed result * and, in case of a crash, restart from the last saved point. * For example, suppose the following call crashes mid-way: * \code * // original call * TasGrid::TasmanianSparseGrid grid = TasGrid::makeLocalPolynomialGrid(...); * constructSurrogate(model, budget, num_parallel, grid, 1.E-6, TasGrid::refine_classic, -1, * std::vector(), std::vector(), "foo"); * \endcode * After the crash, Tasmanian will attempt to recover the computed samples from * files "foo" and "foo_old", if the files don't exist or do not contain * valid recovery data, the procedure will restart from scratch. * However, if the files were saved successfully the procedure will restart * mid-way and samples will not have to be recomputed. */ template void constructSurrogate(ModelSignature model, size_t max_num_points, size_t num_parallel_jobs, size_t max_samples_per_job, TasmanianSparseGrid &grid, double tolerance, TypeRefinement criteria, int output = -1, std::vector const &level_limits = std::vector(), std::string const &checkpoint_filename = std::string()){ if (!grid.isLocalPolynomial() && !grid.isWavelet()) throw std::runtime_error("ERROR: construction (with tolerance and criteria) called for a grid that is not local polynomial or wavelet."); constructCommon (model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, [&](TasmanianSparseGrid &g)->std::vector{ return g.getCandidateConstructionPoints(tolerance, criteria, output, level_limits); }, checkpoint_filename); } /*! * \ingroup TasmanianAddonsConstruct * \brief Construct a sparse grid surrogate to the model defined by the lambda. * * Uses the user provided \b anisotropic_weights to order the samples by importance * and calles the anisotropic overload of TasmanianSparseGrid::getCandidateConstructionPoints(). * Otherwise the function is identical to TasGrid::constructSurrogate(). * * \b WARNING: anisotropic refinement does not target a tolerance, * thus sampling will continue until the budget is exhausted * or the level limits are reached (which will produce a full tensor grid). */ template void constructSurrogate(ModelSignature model, size_t max_num_points, size_t num_parallel_jobs, size_t max_samples_per_job, TasmanianSparseGrid &grid, TypeDepth type, std::vector const &anisotropic_weights = std::vector(), std::vector const &level_limits = std::vector(), std::string const &checkpoint_filename = std::string()){ constructCommon (model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, [&](TasmanianSparseGrid &g)->std::vector{ return g.getCandidateConstructionPoints(type, anisotropic_weights, level_limits); }, checkpoint_filename); } /*! * \ingroup TasmanianAddonsConstruct * \brief Construct a sparse grid surrogate to the model defined by the lambda. * * Uses anisotropic weights to order the samples by importance, * starts with a fully isotropic grid until enough points are loaded to allow to estimate the weights. * The procedure uses the anisotropic overload of TasmanianSparseGrid::getCandidateConstructionPoints(), * otherwise the function is identical to TasGrid::constructSurrogate(). * * \b WARNING: anisotropic refinement does not target a tolerance, * thus sampling will continue until the budget is exhausted * or the level limits are reached (which will produce a full tensor grid). */ template void constructSurrogate(ModelSignature model, size_t max_num_points, size_t num_parallel_jobs, size_t max_samples_per_job, TasmanianSparseGrid &grid, TypeDepth type, int output, std::vector const &level_limits = std::vector(), std::string const &checkpoint_filename = std::string()){ constructCommon (model, max_num_points, num_parallel_jobs, max_samples_per_job, grid, [&](TasmanianSparseGrid &g)->std::vector{ return g.getCandidateConstructionPoints(type, output, level_limits); }, checkpoint_filename); } } #endif TASMANIAN-8.1/Addons/tsgExoticQuadrature.hpp000066400000000000000000000472671470551176200206550ustar00rootroot00000000000000/* * Copyright (c) 2021, Miroslav Stoyanov & William Kong * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND * IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE * OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL * ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES * RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING * FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_EXOTICQUADRATURE_HPP #define __TASMANIAN_ADDONS_EXOTICQUADRATURE_HPP /*! * \internal * \file tsgExoticQuadrature.hpp * \brief Header to include the exotic quadrature templates. * \author Miroslav Stoyanov * \ingroup TasmanianAddonsExoticQuad * * \endinternal */ #include "tsgAddonsCommon.hpp" /*! * \defgroup TasmanianAddonsExoticQuad Exotic Quadrature * \ingroup TasmanianAddons * * \par Exotic Quadrature * The Exotic Quadrature module of Tasmanian offers a collection of functions for generating one dimensional quadrature rules * with weight functions that are not strictly non-negative. The quadrature rules are loaded inside TasGrid::CustomTabulated * objects and be used in calls to TasmanianSparseGrid::makeGlobalGrid() to extend those to a multidimensional context. * * \par * The integral of interest has the form \f$ \int_{-1}^{1} f(x) \rho(x) dx \f$ and it differs from the classical Gaussian * rules by allowing the weight function \f$ \rho(x) \f$ to be negative in portions of the domain. * We still require that the weight is integrable and bounded from below, i.e., \f$ \int_{-1}^{1} | \rho(x) | dx < \infty \f$ * and \f$ \rho(x) \geq c > -\infty \f$. * * \par * The quadrature consists of two components, one is a quadrature that uses classical Gaussian construction using * the root of polynomials that are orthogonal with respect to a shifted positive weight \f$ \rho(x) + c \geq 0 \f$ * and a correction term using Gauss-Legendre rule scaled by -c. * While the asymptotic convergence rate is inferior to that of Gauss-Legendre, for small number of points * the accuracy of the combined quadrature rule can be significantly greater. * This advantage is further magnified in a sparse grid context where reaching the asymptotic regime for Gauss-Legendre * may require a prohibitive number of points due to the curse of dimensionality. * * \par * The weight can be defined either with a C++ lambda expression or a one-dimensional TasmanianSparseGrid object. * The lambda expression will be evaluated at a large number of Gauss-Legendre points that will be used for * a reference quadrature to build the orthogonal polynomial basis. * In the case of a sparse grid object, only the loaded points and quadrature weights will be used, * and no interpolation will be performed inbetween (i.e., we circumvent potential interpolation error). */ namespace TasGrid { /*! * \internal * \ingroup TasmanianAddonsExoticQuad * \brief Specifies which algorithm is used in computing the Gauss quadrature points and weights in getGaussNodesAndWeights(). * * \endinternal */ static int gauss_quadrature_version = 1; /*! * \internal * \ingroup TasmanianAddonsExoticQuad * \brief Evaluates a polynomial with roots given by \b roots at the point \b x. * * The polynomial is defined by a simple product of (x - roots[i]) and will not be normalized. * \endinternal */ inline double poly_eval(const std::vector &roots, double x) { double eval_value = 1.0; for (auto r : roots) eval_value *= (x - r); return eval_value; } /*! * \internal * \ingroup TasmanianAddonsExoticQuad * \brief Evaluates a Lagrange basis polynomial at a point \b x. * * The Lagrange basis at idx is 1 when x = roots[idx] and 0 for all other roots. * \param idx is the index of the Lagrange polynomial * \param roots is the point set the defines the Lagrange polynomials * \param x is the point of interest * \endinternal */ inline double lagrange_eval(size_t idx, const std::vector &roots, double x) { double eval_value = 1.0; for (size_t i=0; i inline void getGaussNodesAndWeights(const int n, const std::vector &ref_points, const std::vector &ref_weights, std::vector> &points_cache, std::vector> &weights_cache) { #ifndef Tasmanian_ENABLE_BLAS // If BLAS is not enabled, we must use an implementation that does not require it. if (gauss_quadrature_version == 1) { gauss_quadrature_version = 2; } #endif // Compute the roots incrementally. assert(ref_points.size() == ref_weights.size()); assert(ref_points.size() > 0); double mu0 = 0.0; for (auto &w : ref_weights) mu0 += w; std::vector poly_m1_vals(ref_points.size(), 0.0), poly_vals(ref_points.size(), 1.0); std::vector diag, offdiag; points_cache.resize(n); weights_cache.resize(n); for (int i=0; i= 1) { double sqr_offdiag_numr = 0.0; double sqr_offdiag_denm = 0.0; for (size_t j=0; j(points_cache[i].size(), 0.0); for (size_t j=0; j dummy_diag = diag; std::vector dummy_offdiag = offdiag; TasmanianTridiagonalSolver::decompose(dummy_diag, dummy_offdiag, mu0, points_cache[i], weights_cache[i]); } else { throw std::invalid_argument("ERROR: gauss_quadrature_version must be a valid number!"); } // Update the values of the polynomials at ref_points. std::swap(poly_m1_vals, poly_vals); std::transform(ref_points.begin(), ref_points.end(), poly_vals.begin(), [&points_cache, i](double x){return poly_eval(points_cache[i], x);}); } } /*! * \internal * \ingroup TasmanianAddonsExoticQuad * \brief Generate the exotic quadrature points and weights and load them into a TasGrid::CustomTabulated object. * * The method calls getGaussNodesAndWeights() and adds the Gauss-Legendre correction. * * \param n is the number of levels to compute * \param shift is the correction term applied to the weight function to enforce positivity * \param shifted_weights are the reference quadrature points multiplied by the values of the shifted weight function at the reference points * \param ref_points are the reference quadrature points * \param description is the human readable string to identify the quadrature rule * \param is_symmetric indicates whether we can use algorithm modifications that can improve stability * \endinternal */ inline TasGrid::CustomTabulated getShiftedExoticQuadrature(const int n, const double shift, const std::vector &shifted_weights, const std::vector &ref_points, const char* description, const bool is_symmetric = false) { // Create the set of points (roots) and weights for the first term. assert(shifted_weights.size() == ref_points.size()); std::vector> points_cache, weights_cache; if (is_symmetric) { getGaussNodesAndWeights(n, ref_points, shifted_weights, points_cache, weights_cache); } else { getGaussNodesAndWeights(n, ref_points, shifted_weights, points_cache, weights_cache); } // Create and append the set of correction points and weights for the second term only if the shift is nonzero. if (shift != 0.0) { for (int i=0; i correction_points, correction_weights; TasGrid::OneDimensionalNodes::getGaussLegendre(static_cast(init_size), correction_weights, correction_points); for (auto &w : correction_weights) w *= -shift; if (correction_points.size() % 2 == 1 && is_symmetric) { // Zero out for stability. correction_points[(correction_points.size() - 1) / 2] = 0.0; } // Account for duplicates up to a certain tolerance. for (size_t j=0; j(k); break; } } if (nonunique_idx == -1) { points_cache[i].push_back(correction_points[j]); weights_cache[i].push_back(correction_weights[j]); } else { weights_cache[i][nonunique_idx] += correction_weights[j]; } } } } // Output to a CustomTabulated instance. std::vector num_nodes(n), precision(n); for (int i=0; i(points_cache[i].size()); precision[i] = 2 * (i + 1) - 1; } return TasGrid::CustomTabulated(std::move(num_nodes), std::move(precision), std::move(points_cache), std::move(weights_cache), description); } /*! * \internal * \ingroup TasmanianAddonsExoticQuad * \brief Multiplies the reference quadrature weights by the shifted values of the weight function. * * \param vals are the values of the exotic weight function at the reference quadrature points * \param shift is a real-valued scalar that ensures all \b vals[i] + \b shift are positive * \param ref_weights are the reference quadrature weights, will be overwritten with the result ref_weights[i] * (vals[i] + shift) * * \throws std::invalid_argument if \b vals[i] + \b shift is negative for some index i * * \endinternal */ inline void shiftReferenceWeights(std::vector const &vals, double shift, std::vector &ref_weights){ assert(ref_weights.size() == vals.size()); if (not std::all_of(vals.begin(), vals.end(), [shift](double x){return (x+shift)>=0.0;})) throw std::invalid_argument("ERROR: shift needs to be chosen so that weight_fn(x)+shift is nonnegative!"); for (size_t k=0; k ref_points = grid.getLoadedPoints(); std::vector shifted_weights = grid.getQuadratureWeights(); std::vector weight_fn_vals = std::vector(grid.getLoadedValues(), grid.getLoadedValues() + grid.getNumLoaded()); shiftReferenceWeights(weight_fn_vals, shift, shifted_weights); return getShiftedExoticQuadrature(num_levels, shift, shifted_weights, ref_points, description, is_symmetric); } /*! * \ingroup TasmanianAddonsExoticQuad * \brief Similar to getExoticQuadrature() but the weight function is defined by a lambda expression. * * Constructs a CustomTabulated object holding the points and weights for the different levels of the quadrature * for the given parameter \b weight_fn. The \b num_ref_points parameter sets the number of reference points * from a Gauss-Legendre quadrature that will be used to compute the inner-product integrals * that define the orthogonal polynomials. */ inline TasGrid::CustomTabulated getExoticQuadrature(const int num_levels, const double shift, std::function weight_fn, const int num_ref_points, const char* description, const bool is_symmetric = false) { std::vector shifted_weights, ref_points, weight_fn_vals(num_ref_points); TasGrid::OneDimensionalNodes::getGaussLegendre(num_ref_points, shifted_weights, ref_points); std::transform(ref_points.begin(), ref_points.end(), weight_fn_vals.begin(), weight_fn); shiftReferenceWeights(weight_fn_vals, shift, shifted_weights); return getShiftedExoticQuadrature(num_levels, shift, shifted_weights, ref_points, description, is_symmetric); } } // namespace(TasGrid) #endif TASMANIAN-8.1/Addons/tsgLoadNeededValues.hpp000066400000000000000000000236631470551176200205220ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_LOADNEEDEDVALS_HPP #define __TASMANIAN_ADDONS_LOADNEEDEDVALS_HPP /*! * \internal * \file tsgLoadNeededValues.hpp * \brief Templates for non-adaptive sampling from lambda models. * \author Miroslav Stoyanov * \ingroup TasmanianAddonsCommon * * Templates that call call a model at the needed points and * load the corresponding model values. * \endinternal */ #include "tsgAddonsCommon.hpp" /*! * \ingroup TasmanianAddons * \addtogroup TasmanianAddonsLoadNeededVals Static Load Model Values * * Handy templates to automate the common use case of evaluating * a model at the needed (or loaded) points and feeding the values to the grid. */ namespace TasGrid{ /*! * \ingroup TasmanianAddonsLoadNeededVals * \brief Loads the current grid with model values, does not perform any refinement. * * Loads model values into the grid using the provided lambda function, * the model can be computed either sequentially or in parallel. * This is a non-adaptive procedure, i.e., the points will not be changes * only the associated model values will be modified. * * \tparam parallel_construction defines whether to run in parallel or sequential mode. * \tparam overwrite_loaded defines whether to overwrite the currently loaded model * values or to assign values to the needed points. * * \param model is the lambda representation of a model with inputs \b x and outputs \b y, * the lambda must accept arrays with size equal to the grid dimensions and * outputs. For each \b x, the \b y must be overwritten with the corresponding * model values. If parallel sampling is uses, then \b thread_id will be * a unique number between 0 and \b num_threads-1 associated with the running * thread. The id can help associate each thread with additional external resources, * e.g., a separate CUDA device can be associated with each thread. * * \param grid is the sparse grid that will be loaded. The grid must not be set for construction * and the number of inputs must be positive. The method grid.loadNeededValues() * will be called with values corresponding to the model outputs at either * the loaded or the needed points. * * \param num_threads is the number of parallel calls to the \b model lambda. * If set to zero, sequential mode will be used without launching any threads, * the number is ignored in sequential mode. * Note that this is using the C++ native std::thread as opposed to OpenMP. * * \throws std::runtime_error if grid.isUsingConstruction() is true or if grid.getNumOutputs() is zero. * * Example: * \code * // construct a grid for 10-th order global polynomials * auto grid = TasGrid::makeGlobalGrid(4, 1, 10, TasGrid::type_iptotal, TasGrid::rule_leja); * // note that the grid is set to 4 inputs and 1 output, the model function should be the same * auto model = [](double const x[], double y[], size_t)->void{ * y[0] = std::exp(x[0] + x[1] + x[2] + x[3]); * } * loadNeededValues(model, grid, 4); // using parallel sampling with 4 threads * // at this point, grid is a 10-th order polynomial approximation to exp(x0 + x2 + x3 + x4) * \endcode */ template void loadNeededValues(std::function model, TasmanianSparseGrid &grid, size_t num_threads){ int num_points = (overwrite_loaded) ? grid.getNumLoaded() : grid.getNumNeeded(); int num_outputs = grid.getNumOutputs(); if (grid.isUsingConstruction()) throw std::runtime_error("ERROR: cannot call loadNeededPoints() addon when isUsingConstruction() is true"); if (num_outputs == 0) throw std::runtime_error("ERROR: cannot call loadNeededPoints() addon when the grid has no outputs"); if (num_points == 0) return; // nothing to do here if (overwrite_loaded && (grid.getNumNeeded() != 0)) grid.clearRefinement(); // using loaded points only, clear the refinement // get the points and values auto points = (overwrite_loaded) ? grid.getLoadedPoints() : grid.getNeededPoints(); std::vector values(Utils::size_mult(num_points, num_outputs)); // divide logically into strips Utils::Wrapper2D xwrap(grid.getNumDimensions(), points.data()); Utils::Wrapper2D ywrap(num_outputs, values.data()); if (parallel_construction && (num_threads > 0)){ std::vector checked_out(num_points, false); std::mutex checked_out_lock; std::vector workers; workers.reserve(num_threads); for(size_t thread_id=0; thread_idvoid{ int sample = 0; do{ { // find the next sample std::lock_guard lock(checked_out_lock); while ((sample < num_points) && checked_out[sample]) sample++; if (sample < num_points) checked_out[sample] = true; } if (sample < num_points) // if found, compute the next sample model(xwrap.getStrip(sample), ywrap.getStrip(sample), thread_id); }while(sample < num_points); } ); } for(auto &w : workers) w.join(); // wait till finished }else{ for(int i=0; i void loadNeededValues(std::function const &x, std::vector &y, size_t thread_id)> model, TasmanianSparseGrid &grid, size_t num_threads){ int num_dimensions = grid.getNumDimensions(); int num_outputs = grid.getNumOutputs(); loadNeededValues( [&](double const x[], double y[], size_t thread_id)->void{ std::vector vecy(num_outputs); model(std::vector(x, x + num_dimensions), vecy, thread_id); std::copy(vecy.begin(), vecy.end(), y); }, grid, num_threads); } /*! * \ingroup TasmanianAddonsLoadNeededVals * \brief Alias to loadNeededValues(), array variant. */ template void loadNeededPoints(std::function model, TasmanianSparseGrid &grid, size_t num_threads){ loadNeededValues(model, grid, num_threads); } /*! * \ingroup TasmanianAddonsLoadNeededVals * \brief Alias to loadNeededValues(), vector variant. */ template void loadNeededPoints(std::function const &x, std::vector &y, size_t thread_id)> model, TasmanianSparseGrid &grid, size_t num_threads){ loadNeededValues(model, grid, num_threads); } } #endif TASMANIAN-8.1/Addons/tsgLoadUnstructuredPoints.hpp000066400000000000000000000421201470551176200220470ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_LOADUNSTRUCTURED_HPP #define __TASMANIAN_ADDONS_LOADUNSTRUCTURED_HPP /*! * \internal * \file tsgLoadUnstructuredPoints.hpp * \brief Templates for using unstructured data. * \author Miroslav Stoyanov * \ingroup TasmanianAddonsCommon * * Templates that infer the surrogate coefficients from unstructured data. * \endinternal */ #include "tsgLoadNeededValues.hpp" /*! * \ingroup TasmanianAddons * \addtogroup TasmanianAddonsLoadUnstructured Load from Unstructured Point Set * * Templates that infer sparse grid coefficients from a set of unstructured points and model values. * These work very similar to TasGrid::loadNeededPoints(), but the data is not assumed to align * to the sparse grid. While removing some of the restrictions, the unstructured approach * always requires more data to achieve the same level of accuracy compared to the carefully chosen * points, and the approximation is valid only in the convex hull of the data, i.e., * extrapolating outside of the data-cloud is not mathematically stable. * In the interior of the data-cloud, the accuracy of the surrogate is very sensitive to * the distribution of the points and good accuracy can be achieved only in areas where * the points are sufficiently dense. * * The inference usually relies on solving some linear or non-linear problem * which may not be stable and may require additional regularization, especially if the data * is not sufficient to provide values for all hierarchical coefficients, e.g., all data falls outside of the support * of some locally supported basis functions. */ namespace TasGrid{ /*! * \internal * \ingroup TasmanianAddonsLoadUnstructured * \brief Returns true if the grid has a GPU algorithm for computing the hierarchical basis. * * \endinternal */ inline bool hasGPUBasis(TasmanianSparseGrid const &grid){ return AccelerationMeta::isAvailable(accel_gpu_cuda) and not (grid.isLocalPolynomial() and ((grid.getOrder() < 0) or (grid.getOrder() > 2))) and not (grid.isWavelet() and grid.getOrder() == 3); } /*! * \internal * \ingroup TasmanianAddonsLoadUnstructured * \brief Generates the coefficients and solves the least-squares problem. * * The template assumes that the arrays are allocated on the GPU device * and the \b model_values are set to the correct size that would include padding * needed for the regularization (note that the padded may not be initialized). * The basis matrix will be constructed on the GPU and must fit in memory. * \endinternal */ template void generateCoefficientsGPU(double const data_points[], int num_data, scalar_type model_values[], double tolerance, TasmanianSparseGrid &grid){ AccelerationContext const *acceleration = grid.getAccelerationContext(); int num_outputs = grid.getNumOutputs(); int num_points = grid.getNumPoints(); int num_equations = (tolerance > 0.0) ? num_data + num_points : num_data; GpuVector basis_matrix(acceleration, num_equations, num_points); grid.evaluateHierarchicalFunctionsGPU(data_points, num_data, reinterpret_cast(basis_matrix.data())); if (tolerance > 0.0){ double correction = std::sqrt(tolerance); constexpr long long esize = (std::is_same::value) ? 1 : 2; long long num_total = static_cast(num_points) * static_cast(num_points) * esize; TasGpu::fillDataGPU(acceleration, 0.0, num_total, 1, reinterpret_cast(basis_matrix.data() + Utils::size_mult(num_data, num_points))); long long stride = static_cast(num_points + 1) * esize; TasGpu::fillDataGPU(acceleration, correction, num_points, stride, reinterpret_cast(basis_matrix.data() + Utils::size_mult(num_data, num_points))); TasGpu::fillDataGPU(acceleration, 0.0, esize * num_outputs * num_points, 1, reinterpret_cast(model_values + Utils::size_mult(num_data, num_outputs))); } TasmanianDenseSolver::solvesLeastSquaresGPU(acceleration, num_equations, num_points, basis_matrix.data(), num_outputs, model_values); } /*! * \internal * \ingroup TasmanianAddonsLoadUnstructured * \brief Generates the coefficients and solves the least-squares problem. * * The template assumes that the arrays are allocated on the CPU. * The basis matrix is build on the CPU, unless MAGMA acceleration is enabled; * in the magma case, the matrix will be build on the GPU by using several * rows at a time as to avoid overfilling the GPU memory (out-of-core). * \endinternal */ template Data2D generateCoefficients(double const data_points[], int num_data, double const model_values[], double tolerance, TasmanianSparseGrid &grid){ int num_dimensions = grid.getNumDimensions(); int num_outputs = grid.getNumOutputs(); int num_points = grid.getNumPoints(); int num_equations = (tolerance > 0.0) ? num_data + num_points : num_data; AccelerationContext const *acceleration = grid.getAccelerationContext(); Data2D basis_matrix(num_points, num_equations, 0.0); Data2D coefficients(num_outputs, num_equations, 0.0); if (acceleration->mode == accel_gpu_magma and hasGPUBasis(grid)){ int mem_usage = 268435456 / ((std::is_same::value) ? 1 : 2); // 2GB of double numbers if (grid.getGPUMemory(acceleration->device) < 2048) mem_usage /= 2; // use minimum of 1GB int num_batch = std::min(num_data, mem_usage / num_points); if (num_batch < 128){ // cannot use the GPU with less than 128 entries, might as well use the CPU grid.evaluateHierarchicalFunctions(data_points, num_data, reinterpret_cast(basis_matrix.data())); }else{ acceleration->setDevice(); GpuVector gpu_points(acceleration, num_dimensions, num_batch); GpuVector gpu_matrix(acceleration, num_points, num_batch); for(int i = 0; i < num_data; i += num_batch){ int num_this_batch = std::min(num_batch, num_data - i); gpu_points.load(acceleration, Utils::size_mult(num_this_batch, num_dimensions), data_points + Utils::size_mult(i, num_dimensions)); grid.evaluateHierarchicalFunctionsGPU(gpu_points.data(), num_this_batch, reinterpret_cast(gpu_matrix.data())); gpu_matrix.unload(acceleration, Utils::size_mult(num_this_batch, num_points), basis_matrix.getStrip(i)); } } }else{ grid.evaluateHierarchicalFunctions(data_points, num_data, reinterpret_cast(basis_matrix.data())); } if (tolerance > 0.0){ double correction = std::sqrt(tolerance); for(int i=0; i specified by \b scalar_type. * \endinternal */ template inline void loadUnstructuredDataL2tmpl(double const data_points[], int num_data, double const model_values[], double tolerance, TasmanianSparseGrid &grid){ if (grid.empty()) throw std::runtime_error("Cannot use loadUnstructuredDataL2() with an empty grid."); if (grid.getNumNeeded() != 0) grid.mergeRefinement(); AccelerationContext const *acceleration = grid.getAccelerationContext(); if (acceleration->mode == accel_none) throw std::runtime_error("The loadUnstructuredDataL2() method cannot be used with acceleration mode accel_none."); int num_dimensions = grid.getNumDimensions(); int num_outputs = grid.getNumOutputs(); int num_points = grid.getNumPoints(); int num_equations = (tolerance > 0.0) ? num_data + num_points : num_data; Data2D coefficients = [&]()->Data2D{ if (acceleration->mode == accel_gpu_cuda and hasGPUBasis(grid)){ acceleration->setDevice(); GpuVector gpu_points(acceleration, num_dimensions, num_data, data_points); GpuVector gpu_values(acceleration, num_outputs, num_equations); TasGpu::load_n(acceleration, model_values, Utils::size_mult(num_outputs, num_data), gpu_values.data()); generateCoefficientsGPU(gpu_points.data(), num_data, gpu_values.data(), tolerance, grid); return Data2D(num_outputs, num_equations, gpu_values.unload(acceleration)); }else{ return generateCoefficients(data_points, num_data, model_values, tolerance, grid); } }(); // do the real-complex split (used in Fourier grids) if (std::is_same>::value){ std::vector real_coeffs(Utils::size_mult(2 * grid.getNumOutputs(), grid.getNumPoints())); auto icoeff = coefficients.begin(); for(size_t i=0; i(coefficients.data())); } } /*! * \ingroup TasmanianAddonsLoadUnstructured * \brief Construct a sparse grid surrogate using a least-squares fit. * * Constructs the coefficients of the grid using a least-squares fit \f$ \min_c \| G_c(x) - Y \|_2 \f$, * where \b c indicates the hierarchical coefficients of the grid, \b x indicates the data-points * and \b Y is the associated model outputs. The problem is set as a linear system of equations * so that \f$ G_c(x) = H c \f$ where \b H is the matrix of hierarchical coefficients. * Depending on the distribution of the points and/or the type of grid, the system may not be well posed, * hence the simple regularization option to add \b tolerance multiplied by the norm of \b c. * * \param data_points array of data points similar to TasmanianSparseGrid::loadConstructedPoints() * with size grid.getNumDimensions() by \b num_data * \param num_data the number of data points * \param model_values array of model values corresponding to the \b data_points, the size is grid.getNumOutputs() by \b num_data * \param tolerance if positive, will add regularization to the least-squares problem, must be less than the accuracy * of the surrogate so that it will not affect the approximation error; * if set to zero or less, no regularization will be used but depending on the type of grid and * the distribution of the points, the problem may not be well posed * \param grid is a non-empty grid, if a refinement has been set, it will be merged with the existing points before inference * * \throws std::runtime_error if the grid is empty or \b accel_none is used * \throws std::runtime_error on various cuda errors, e.g., not enough GPU memory, * or if the matrix \b G_c does not have a full column rank, e.g., regularization tolerance * is \b 0 and the data is not sufficient to provide coefficients for all basis functions * * The problem requires the QR factorization of \b G_c and the solution against multiple right hand sides * corresponding to the model outputs. This is computationally very expensive and cannot be done without an * appropriate acceleration mode: * - \b accel_cpu_blas will perform all operations on the CPU using OpenMP and the BLAS and LAPACK implementations, * OpenMP is optional but recommended * - \b accel_gpu_cublas will form \b G_c on the CPU, but then the matrix will be moved to the GPU device and * will perform the solver stage using cuBlas and cuSolverDn * - \b accel_gpu_cuda will form \b G_c on the GPU and perform the solve using cuBlas and cuSolverDn, * if the there is no GPU algorithm for the corresponding TasmanianSparseGrid::evaluateHierarchicalFunctionsGPU() * then the CPU will be used identical to the cublas mode * - \b accel_gpu_magma will form \b G_c on the GPU device, but will do so in batches as to limit the GPU memory * used at a given time, then the linear algebra will be performed using the MAGMA out-of-core methods * * The cuda and cublas modes, require that the data and the associated matrices fit in the memory of the GPU device, * MAGMA does not have that restriction. */ inline void loadUnstructuredDataL2(double const data_points[], int num_data, double const model_values[], double tolerance, TasmanianSparseGrid &grid){ if (grid.isFourier()){ loadUnstructuredDataL2tmpl>(data_points, num_data, model_values, tolerance, grid); }else{ loadUnstructuredDataL2tmpl(data_points, num_data, model_values, tolerance, grid); } } /*! * \ingroup TasmanianAddonsLoadUnstructured * \brief Overload that used vectors and infers the number of data points from the size of the vectors. * * See TasGrid::loadUnstructuredDataL2() for details, in addition * * \throws std::runtime_error if the sizes of the \b data_points and \b model_values do not match */ inline void loadUnstructuredDataL2(std::vector const &data_points, std::vector const &model_values, double tolerance, TasmanianSparseGrid &grid){ if (grid.empty()) throw std::runtime_error("Cannot use loadUnstructuredDataL2() with an empty grid."); int num_data = static_cast(data_points.size() / grid.getNumDimensions()); if (model_values.size() < Utils::size_mult(num_data, grid.getNumOutputs())) throw std::runtime_error("In loadUnstructuredDataL2(), provided more points than data."); loadUnstructuredDataL2(data_points.data(), num_data, model_values.data(), tolerance, grid); } } #endif TASMANIAN-8.1/Addons/tsgMPIConstructGrid.hpp000066400000000000000000000564341470551176200205200ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_MPICONSTRUCTGRID_HPP #define __TASMANIAN_ADDONS_MPICONSTRUCTGRID_HPP /*! * \internal * \file tsgMPIConstructGrid.hpp * \brief Sparse Grids construction through sampling and MPI. * \author Miroslav Stoyanov * \ingroup TasmanianAddonsCommon * * Templates that construct a sparse grid with sampling distributed across an MPI communicator. * \endinternal */ #include "tsgMPIScatterDream.hpp" #include "tsgConstructSurrogate.hpp" /*! * \ingroup TasmanianAddons * \addtogroup TasmanianAddonsMPIConstruct MPI Automated Surrogate Construction Procedure * * Distributed sampling procedure, construction similar to TasGrid::constructSurrogate() * but the parallelism is associated with different ranks in an MPI communicator. * These templates require Tasmanian_ENABLE_MPI=ON. */ #ifdef Tasmanian_ENABLE_MPI namespace TasGrid{ /*! * \ingroup TasmanianAddonsMPIConstruct * \brief Signature of a model function to be used in the MPI construction procedures. * * The logic is identical to the TasGrid::ModelSignature used in the TasGrid::constructSurrogate() * templates, with the exception of the removal of the thread-id. * In an MPI context, the thread-id is replaced by the MPI rank which can be queried using MPI_Comm_rank(). */ using ModelSignatureMPI = std::function const &x, std::vector &y)>; /*! * \internal * \ingroup TasmanianAddonsMPIConstruct * \brief MPI construction algorithm using generic candidates procedure. * * Implements the MPI algorithm with generic refinement procedure given to TasGrid::constructCommon(). * \endinternal */ template void mpiConstructCommon(ModelSignatureMPI model, int num_dimensions, int num_outputs, size_t max_num_points, size_t max_samples_per_job, size_t max_num_ranks, int tagx, int tagy, int root, MPI_Comm comm, TasmanianSparseGrid &grid, std::function(TasmanianSparseGrid &)> candidates, std::string const &checkpoint_filename){ int num_ranks; MPI_Comm_size(comm, &num_ranks); // force max_num_ranks between 1 and num_ranks max_num_ranks = std::max(std::min(max_num_ranks, size_t(num_ranks)), size_t(1)); int const me = getMPIRank(comm); // my rank within the comm std::vector thread_to_rank(num_ranks); // map the thread id to the rank, root is used last std::iota(thread_to_rank.begin(), thread_to_rank.begin() + root, 0); std::iota(thread_to_rank.begin() + root, thread_to_rank.end(), root + 1); thread_to_rank.back() = root; size_t max_message = sizeof(double) * Utils::size_mult(num_dimensions, max_samples_per_job) + sizeof(size_t); if (use_initial_guess == with_initial_guess) max_message += sizeof(double) * Utils::size_mult(num_outputs, max_samples_per_job) + sizeof(size_t); if (me == root){ // main sampler MPI_Barrier(comm); constructCommon( [&](std::vector const &x, std::vector &y, size_t thread_id)->void{ int rankid = thread_to_rank[thread_id]; if (rankid == root){ model(x, y); // thread belongs to this rank, do work locally }else{ std::stringstream ss; // pack x and y into a message IO::writeNumbers(ss, x.size()); IO::writeVector(x, ss); if (use_initial_guess == with_initial_guess){ // pack y only if used IO::writeNumbers(ss, y.size()); IO::writeVector(y, ss); } MPI_Send(ss.str().c_str(), (int) (ss.str().size()), MPI_BYTE, rankid, tagx, comm); // send x MPI_Status status; MPI_Request request; y.resize(Utils::size_mult(num_outputs, x.size() / num_dimensions)); MPI_Irecv(y.data(), (int) y.size(), MPI_DOUBLE, rankid, tagy, comm, &request); // receive y MPI_Wait(&request, &status); // wait for the result from the model } }, max_num_points, max_num_ranks, max_samples_per_job, grid, candidates, checkpoint_filename); std::stringstream stop_message; IO::writeNumbers(stop_message, size_t(0)); if (use_initial_guess == with_initial_guess) IO::writeNumbers(stop_message, size_t(0)); // pass 0 for y for(size_t id=0; id message_buffer(max_message); std::vector x, y; do{ MPI_Status status; MPI_Recv(message_buffer.data(), (int) message_buffer.size(), MPI_BYTE, root, tagx, comm, &status); // receive x // unpack the message VectorToStreamBuffer data_buffer(message_buffer); // do not modify buff after this point std::istream is(&data_buffer); x = IO::readVector(is, IO::readNumber(is)); if (use_initial_guess == with_initial_guess){ // unpack y, if necessary y = IO::readVector(is, IO::readNumber(is)); }else{ y.resize(Utils::size_mult(num_outputs, x.size() / num_dimensions)); } if (!x.empty()){ model(x, y); // call the model MPI_Send(y.data(), (int) (y.size()), MPI_DOUBLE, root, tagy, comm); // send y } }while(!x.empty()); } } } /*! * \ingroup TasmanianAddonsMPIConstruct * \brief Construct a sparse grid surrogate to the model defined by the lambda, MPI version. * * The logic is the same as in TasGrid::constructSurrogate(), construct adaptive sparse grid * surrogate to the mode defined by the lambda using parallel computations. * The model will be executed with different inputs \b x on different ranks within the MPI communicator. * All ranks of across the communicator must make an identical call with identical parameters * before the \b grid. The grid and the refinement and checkpoint parameters will be used * only by the \b root rank and will not be addressed by the rest. * * \par MPI and Multi-Threading * This template will call TasGrid::constructSurrogate() and it will spawn a separate thread * for each active ranks within the communicator. Thus, MPI must support multi-threading * and the multi-threaded initialization call must be used: * \code * // instead of calling MPI_Init() call the following * int threads_available; * MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &threads_available); * if (threads_available != MPI_THREAD_MULTIPLE) * std::cerr << "MPI threading not available, TasGrid::mpiConstructSurrogate() will not work.\n"; * \endcode * Note that the MPIGridSend() and other similar methods do not require multi-threading. * * The list of inputs is very similar to TasGrid::constructSurrogate(), * here we outline the main differences. * * \tparam use_initial_guess defines whether to compute an initial guess for the model outputs * and send that over the communicator. The MPI procedure always runs in parallel mode * hence there is no additional template parameter. * * \param model the inputs \b x and outputs \b y of the model are the same as in * TasGrid::constructSurrogate(); however, there is no thread_id. * Only one call of the model will be executed on each active rank and thus * the MPI native MPI_Comm_rank() can be used in place of the thread_id. * * \param num_dimensions must match \b grid.getNumDimensions(). * This is a required parameter since only the \b root rank is assumed to have * access to the grid, the other ranks need to know the correct dimension without the grid. * \param num_outputs must match \b grid.getNumOutputs(), see \b num_dimensions. * * \param max_num_points defines the computational budget, same as TasGrid::constructSurrogate(). * * \param max_samples_per_job defines the number of samples that will be given to the model * in each call, see TasGrid::constructSurrogate(). * * \param max_num_ranks defines the number of ranks to use, if it exceeds the size of the * communicator then all ranks will be used in the process. If less than the size, * the \b root process will not make calls to the model but it will be working * on the internal grid methods. This is useful when dealing with many points where * the cost of loading points is not negligible. * If the \b max_num_ranks is less than the communicator size minus one, then some of * the ranks will be completely idle (usually the ranks with higher number). * * \param tagx is the MPI_Send() tag to use when communicating the inputs \b x to the worker rank. * \param tagy is the MPI_Send() tag to use when communicating the outputs \b y to the root rank. * * \param root is the MPI rank within the communicator that has the initial copy of the \b grid * as well as the refinement parameters that are identical to TasGrid::constructSurrogate(). * The final result from the construction will be held by the \b root rank only, * the grids for the rest of other ranks will not be accessed. * * \param comm is the MPI communicator where sampling will take place, e.g., MPI_COMM_WORLD. * * \param grid on rank \b root is the grid to be constructed, ignored when the rank is different. * * \param tolerance refinement parameter, see TasGrid::constructSurrogate(). * \param criteria refinement parameter, see TasGrid::constructSurrogate(). * \param output refinement parameter, see TasGrid::constructSurrogate(). * \param level_limits refinement parameter, see TasGrid::constructSurrogate(). * \param scale_correction refinement parameter, see TasGrid::constructSurrogate(). * * \param checkpoint_filename is either empty (skip checkpoints) or the filename to use * to save the intermediate results. Note that only the \b root rank will issue * read/write commands to the files. * * \par Example 1: Model that uses no MPI * Construct a surrogate to a model described by a parametrized system of equations * using a local polynomial gird and arbitrary number of MPI ranks. Rank 0 will be * responsible for the grid construction and computing the initial guess for all * solutions, the rest of the ranks will be calling a solver which makes no MPI calls. * The computational budget is 10,000 points and the solver works with one equation * at a time. * \code * // solves the equation using the initial guess and makes no MPI calls * void solver(std::vector const &inputs, * std::vector &solution, * std::vector &initial guess); * ... * int me, num_ranks, tagx = 11, tagy = 12; * MPI_Comm_rank(MPI_COMM_WORLD, &me); // rank of this process * MPI_Comm_size(comm, &num_ranks); // all ranks * * int num_inputs = ...; // must match the solver * int num_outputs = ...; // must match the solver * * TasGrid::TasmanianSparseGrid grid; * if (me == 0) * grid = TasGrid::makeLocalPolynomialGrid(num_inputs, num_outputs, ...); * * TasGrid::mpiConstructSurrogate( * [&](std::vector const &x, std::vector &y) * ->void{ * auto initial_guess = y; // on input y is the initial guess * std::vector solution; * solver(x, solution, initial_guess); * y = solution; // on output y is the solution * }, * num_dimensions, num_outputs, * 10000, 1, num_ranks - 1, tagx, tagy, 0, MPI_COMM_WORLD, * grid, tolerance, TasGrid::refine_fds, ... ); * * // at this point, grid on rank 0 will hold the surrogate to solver() * // grid on all other processes will be empty() * \endcode * * \par Example 2: Model that works on sub-communicator * Suppose that the model requires multiple MPI ranks for efficient computing * and it can operate on an arbitrary MPI communicator. * In this example, we take the MPI world communicator and we sub-divide it * into many smaller comms, then each sub-communicator will be used to handle * an independent sample. * In this example, all ranks participate in the process, assuming that * the cost of the grid manipulations is negligible compared to the model simulations. * There is no initial guess in the complicated model. * \code * // model that computes the outputs using all ranks on an arbitrary communicator * void model(std::vector const &inputs, * std::vector &outputs, * MPI_Comm comm); * ... * // number of ranks to assign to the communicators for each call to model() * int ranks_per_model = ...; * int world_me, num_ranks, tagx = 11, tagy = 12; * MPI_Comm_rank(MPI_COMM_WORLD, &world_me); // rank of this process in world comm * MPI_Comm comm_worker; // local comm for the work done by the model * // split the world communicator into local ones * MPI_Comm_split(MPI_COMM_WORLD, world_me / ranks_per_model, world_me % ranks_per_model, &comm_worker); * int worker_me; * MPI_Comm_rank(comm_worker, &worker_me); // this procees rank within the worker comm * // create a sub-comm for the processes that would commonicate with Tasmanian * MPI_Comm comm_tasmanian; // communicator for Tasmanian operations * MPI_Comm_split(MPI_COMM_WORLD, (worker_me == 0) ? 0 : MPI_UNDEFINED, world_me, &comm_tasmanian); * int num_tasmanian_ranks; * if (worker_me == 0) MPI_Comm_size(comm_tasmanian, &num_tasmanian_ranks); * int tasmanian_root = 0; // world_me = zero is the same as tasmanian_root = zero * * int num_inputs = ...; // must match the solver * int num_outputs = ...; // must match the solver * * if (worker_me == 0){ * mpiConstructSurrogate( * [&](...)->void{ * MPI_Bcast(... sent x to all ranks in comm_worker ...); * model(..., comm_worker); // participate in this model evaluation * MPI_Gather(... collect all results in this process ...); * }, * num_inputs, num_outputs, 10000, 1, num_tasmanian_ranks, tagx, tagy, * tasmanian_root, comm_tasmanian, * grid, ...); * }else{ * MPI_Bcast(... get x from rank 0 on comm_worker ...); * model(x, outputs, comm_worker); * MPI_Gather(... gather the results in rank 0 on comm_worker ...); * } * \endcode * \b Note: the code above demonstrates the idea of the split world communicator, * an actual Implementation would differ in details and specifics. */ template void mpiConstructSurrogate(ModelSignatureMPI model, int num_dimensions, int num_outputs, size_t max_num_points, size_t max_samples_per_job, size_t max_num_ranks, int tagx, int tagy, int root, MPI_Comm comm, TasmanianSparseGrid &grid, double tolerance, TypeRefinement criteria, int output = -1, std::vector const &level_limits = std::vector(), std::vector const &scale_correction = std::vector(), std::string const &checkpoint_filename = std::string()){ mpiConstructCommon(model, num_dimensions, num_outputs, max_num_points, max_samples_per_job, max_num_ranks, tagx, tagy, root, comm, grid, [&](TasmanianSparseGrid &g)->std::vector{ return g.getCandidateConstructionPoints(tolerance, criteria, output, level_limits, scale_correction); }, checkpoint_filename); } /*! * \ingroup TasmanianAddonsMPIConstruct * \brief Construct a sparse grid surrogate to the model defined by the lambda, MPI version. * * Uses the user provided \b anisotropic_weights to order the samples by importance, * see\n TasmanianSparseGrid::getCandidateConstructionPoints(). * and the overloads to TasGrid::constructSurrogate(). */ template void mpiConstructSurrogate(ModelSignatureMPI model, int num_dimensions, int num_outputs, size_t max_num_points, size_t max_samples_per_job, size_t max_num_ranks, int tagx, int tagy, int root, MPI_Comm comm, TasmanianSparseGrid &grid, TypeDepth type, std::vector const &anisotropic_weights = std::vector(), std::vector const &level_limits = std::vector(), std::string const &checkpoint_filename = std::string()){ mpiConstructCommon(model, num_dimensions, num_outputs, max_num_points, max_samples_per_job, max_num_ranks, tagx, tagy, root, comm, grid, [&](TasmanianSparseGrid &g)->std::vector{ return g.getCandidateConstructionPoints(type, anisotropic_weights, level_limits); }, checkpoint_filename); } /*! * \ingroup TasmanianAddonsMPIConstruct * \brief Construct a sparse grid surrogate to the model defined by the lambda, MPI version. * * Uses anisotropic weights to order the samples by importance, * starts with a fully isotropic grid until enough points are loaded to allow to estimate the weights, * see TasmanianSparseGrid::getCandidateConstructionPoints(). * and the overloads to TasGrid::constructSurrogate(). */ template void mpiConstructSurrogate(ModelSignatureMPI model, int num_dimensions, int num_outputs, size_t max_num_points, size_t max_samples_per_job, size_t max_num_ranks, int tagx, int tagy, int root, MPI_Comm comm, TasmanianSparseGrid &grid, TypeDepth type, int output, std::vector const &level_limits = std::vector(), std::string const &checkpoint_filename = std::string()){ mpiConstructCommon(model, num_dimensions, num_outputs, max_num_points, max_samples_per_job, max_num_ranks, tagx, tagy, root, comm, grid, [&](TasmanianSparseGrid &g)->std::vector{ return g.getCandidateConstructionPoints(type, output, level_limits); }, checkpoint_filename); } /*! * \ingroup TasmanianAddonsMPIConstruct * \brief Executes the worker (i.e., non-root) portion of the MPI sampling. * * Using any of the TasGrid::mpiConstructSurrogate() overloads, the grid, the budget and the refinement * parameters are accessed only by the root rank, the rest is not used by the workers. * This template can be instantiated for the non-root rank with only the relevant inputs. * * - The call to this method \b must be paired with a call to TasGrid::mpiConstructSurrogate() on the root rank. * - The inputs (including the template parameter) \b must match the ones in the call to TasGrid::mpiConstructSurrogate(). * */ template void mpiConstructWorker(ModelSignatureMPI model, int num_dimensions, int num_outputs, size_t max_samples_per_job, size_t max_num_ranks, int tagx, int tagy, int root, MPI_Comm comm){ TasmanianSparseGrid grid; // workers use an empty grid mpiConstructCommon(model, num_dimensions, num_outputs, 0, max_samples_per_job, max_num_ranks, tagx, tagy, root, comm, grid, [&](TasmanianSparseGrid&)->std::vector{ return std::vector(); }, std::string()); } } #endif // Tasmanian_ENABLE_MPI #endif TASMANIAN-8.1/Addons/tsgMPISampleDream.hpp000066400000000000000000000260711470551176200201120ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_MPISAMPLEDREAM_HPP #define __TASMANIAN_ADDONS_MPISAMPLEDREAM_HPP /*! * \internal * \file tsgMPISampleDream.hpp * \brief DREAM posterior sampling using MPI. * \author Miroslav Stoyanov * \ingroup TasmanianAddonsCommon * * Allows calling some of DREAM templates in a distributed MPI context. * \endinternal */ #include "tsgMPIConstructGrid.hpp" /*! * \ingroup TasmanianAddons * \addtogroup TasmanianAddonsMPIDream MPI Sampling from Posterior * * Procedure to collect samples from a posterior distribution using DREAM. */ #ifdef Tasmanian_ENABLE_MPI namespace TasDREAM{ /*! * \ingroup TasmanianAddonsMPIDream * \brief Class that enables distributed DREAM sampling with MPI. * * Models with many outputs are computationally expensive to sample when used in a Bayesian posterior. * Such models can be distributed across ranks of an MPI communicator and the DREAM candidates * can be computed in parallel, i.e., distributing the work. * Of specific interest are posteriors with likelihood functions that can be expressed as a product (or sum) * of one term per model outputs, e.g., constant or diagonal Gaussian likelihoods. * The actual sampling is performed on a single rank while the values of the probability * distribution at the candidate points is computed by all MPI ranks together (each ranks handling a separate set of inputs). * The high-level algorithm can be expressed with two MPI calls, MPI_Bcast() all candidates * to all ranks, then MPI_Reduce() the result. * See TasGrid::MPIGridScatterOutputs() and TasDREAM::MPILikelihoodScatter() * for ways to distribute a sparse grid model and a likelihood function. * * The usage of this class is very similar to the calls to TasDREAM::posterior() template, * the first two inputs are the local portions of the model and likelihood, * followed by the prior which will only be used on the root rank. * The other inputs define parameters of the MPI side of the algorithm. * The constructor can be inlined in a call to TasDREAM::SampleDREAM(). * * \par MPI Synchronization * The call to the constructor will block all ranks except the root, * all non-root ranks will enter into a worker cycle waiting for candidates from root. * The root process will send-out the unblock signal to all workers whenever the root object is * destroyed or the clear() method is called. * The class can be passed as the probability distribution to TasDREAM::SampleDREAM(), * but only the root rank can compute valid samples, the other ranks will use a no-op function. * If SampleDREAM() is called with an empty TasmanianDREAM state then sampling will not be performed, * thus the class should be coupled with an empty state on each of the non-root ranks; * which helps mirror the code across all ranks and avoid extraneous if-statements. * Here are some valid calls: * * \code * int me; * MPI_Comm_rank(MPI_COMM_WORLD, &me); * auto full_grid = TasGrid::readGrid("foo"); * TasGrid::TasmanianSparseGrid grid; * MPIGridScatterOutputs(full_grid, grid, root, 1, MPI_COMM_WORLD); // distribute the grid * TasDREAM::LikelihoodGaussIsotropic full_likely(...); * TasDREAM::LikelihoodGaussIsotropic likely; * MPILikelihoodScatter(full_likely, likely, root, 1, MPI_COMM_WORLD); // distribute the likelihood * TasDREAM::TasmanianDREAM state = (me == root) ? TasmanianDREAM(...) : TasmanianDREAM(); * TasDREAM::SampleDREAM(..., DistributedPosterior(likely, grid, ..., root, ...), ..., state, ...); * \endcode * Alternatively, the object can also be assigned to a variable: * \code * TasDREAM::DistributedPosterior post(likely, grid, ..., root, ...); * if (me == root) TasDREAM::SampleDREAM(..., post, ...); // the state on non-root ranks is irrelevant * post.clear(); // unblock the non-root ranks * \endcode */ template class DistributedPosterior{ public: /*! * \brief Constructor that sets the parameters for the distribued posterior. * * Constructs a distributed posterior object from local model and likelihood objects. * See the class description for example usage, details on the parameters follow here: * * \tparam form is the same as in the call to TasDREAM::SampleDREAM() and both \b must match. * * \param distributed_model is the local portion of the model, the sub-set of the outputs * must match the set used by the \b likelihood. * \param likelihood is the local portion of the likelihood. Same as in the call to TasDREAM::posterior(). * \param prior will be used only by the root rank, same as in the call to TasDREAM::posterior(). * \param num_inputs must match the dimensions of the state on the root rank, * since the non-root ranks do not need a valid state this parameter is used to synchronize * the dimensions across all ranks. * \param num_chains same as the number set by the state, see the \b num_inputs. * \param mpi_root is the root process that will perform the actual sampling. * \param communicator is the communicator where all ranks reside. */ DistributedPosterior(DreamModel distributed_model, DreamLikelihood likelihood, DreamPrior prior, int num_inputs, int num_chains, int mpi_root, MPI_Comm communicator) : model(distributed_model), likely(likelihood), dist_prior(prior), num_dimensions(num_inputs), num_batch(num_chains), root(mpi_root), me(TasGrid::getMPIRank(communicator)), comm(communicator), x(Utils::size_mult(num_dimensions, num_batch) + 1), y((size_t) num_batch){ if (me != root){ // enter work loop int num_candidates = 1; do{ MPI_Bcast(x.data(), num_dimensions*num_batch+1, MPI_DOUBLE, root, comm); num_candidates = (int) x.back(); // the last entry holds the effective number of candidates if (num_candidates > 0){ // if not the shutdown signal x.resize(Utils::size_mult(num_dimensions, num_candidates)); // set x to the correct size y.resize((size_t) num_candidates); std::vector model_outs; model(x, model_outs); likelihood(form, model_outs, y); MPI_Reduce(y.data(), nullptr, num_candidates, MPI_DOUBLE, ((form == regform) ? MPI_PROD : MPI_SUM), root, comm); x.resize(Utils::size_mult(num_dimensions, num_batch) + 1); } }while(num_candidates > 0); } } //! \brief Destructor, unblocks the non-root ranks (if still blocked). ~DistributedPosterior(){ clear(); } //! \brief Unblocks the non-root ranks, the object cannot be used after this calls (can be destroyed only). void clear(){ if ((me == root) && (!x.empty())){ // send out the shutdown signal x.back() = 0.0; MPI_Bcast(x.data(), num_dimensions*num_batch+1, MPI_DOUBLE, root, comm); } } //! \brief Allows passing the object as an input to TasDREAM::SampleDREAM(). operator DreamPDF(){ if (me == root){ return [&](const std::vector &candidates, std::vector &values)->void{ std::copy_n(candidates.begin(), candidates.size(), x.begin()); int num_candidates = (int) candidates.size() / num_dimensions; x.back() = (double) num_candidates; MPI_Bcast(x.data(), num_dimensions*num_batch+1, MPI_DOUBLE, root, comm); y.resize((size_t) num_candidates); std::vector model_outs; model(candidates, model_outs); likely(form, model_outs, y); MPI_Reduce(y.data(), values.data(), num_candidates, MPI_DOUBLE, ((form == regform) ? MPI_PROD : MPI_SUM), root, comm); std::vector prior_vals(values.size()); dist_prior(form, candidates, prior_vals); auto iv = values.begin(); if (form == regform){ for(auto p : prior_vals) *iv++ *= p; }else{ for(auto p : prior_vals) *iv++ += p; } }; }else{ // no-op distribution return [](const std::vector &, std::vector &)->void{}; } } private: std::function const &x, std::vector &y)> model; std::function &model_outputs, std::vector &likely)> likely; std::function &candidates, std::vector &values)> dist_prior; int num_dimensions, num_batch, root, me; MPI_Comm comm; std::vector x, y; }; } #endif // Tasmanian_ENABLE_MPI #endif TASMANIAN-8.1/Addons/tsgMPIScatterDream.hpp000066400000000000000000000224521470551176200202750ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_ADDONS_MPIDREAMSCATTER_HPP #define __TASMANIAN_ADDONS_MPIDREAMSCATTER_HPP /*! * \internal * \file tsgMPIScatterDream.hpp * \brief DREAM objects send/receive through MPI. * \author Miroslav Stoyanov * \ingroup TasmanianAddonsCommon * * Templates that communicate DREAM objects through an MPI commands. * \endinternal */ #include "tsgMPIScatterGrid.hpp" /*! * \ingroup TasmanianAddons * \addtogroup TasmanianAddonsMPIDREAMSend MPI Send/Receive/Scatter for DREAM * * Methods to send/receive DREAM likelihood objects. * The syntax mimics the raw MPI_Send and MPI_Recv calls, * and the templates require Tasmanian_ENABLE_MPI=ON. */ #ifdef Tasmanian_ENABLE_MPI namespace TasDREAM{ /*! * \ingroup TasmanianAddonsMPIDREAMSend * \brief Send a likelihood to another process in the MPI comm. * * Works with both isotropic and anisotropic Gaussian likelihood * object implemented in Tasmanian. * The usage is very similar to MPI_Send() and TasGrid::MPIGridSend(). * Optionally only some of the outputs can be send over. * * \tparam Likelihood is a Tasmanian likelihood class, currently * LikeliTasDREAM::LikelihoodGaussIsotropic and * LikeliTasDREAM::LikelihoodGaussAnisotropic. * * \param likely is the likelihood to send. * \param destination is the rank of the recipient MPI process. * \param tag is the tag to use for the MPI message. * \param comm is the MPI comm where the source and destination reside. * \param outputs_begin same as in LikelihoodGaussIsotropic::write(). * \param outputs_end same as in LikelihoodGaussIsotropic::write(). * * \return the error code of the MPI_Send() command. * * \b Note: this call must be mirrored by TasDREAM::MPILikelihoodRecv() on the * destination process. */ template int MPILikelihoodSend(Likelihood const &likely, int destination, int tag, MPI_Comm comm, int outputs_begin = 0, int outputs_end = -1){ std::stringstream ss; likely.write(ss, outputs_begin, outputs_end); while(ss.str().size() % 16 != 0) ss << " "; return MPI_Send(ss.str().c_str(), (int) (ss.str().size() / 16), MPI_LONG_DOUBLE, destination, tag, comm); } /*! * \ingroup TasmanianAddonsMPIDREAMSend * \brief Receive a likelihood from another process in the MPI comm. * * Works with both isotropic and anisotropic Gaussian likelihood * object implemented in Tasmanian. * The usage is very similar to MPI_Recv() and TasGrid::MPIGridRecv(). * * \tparam Likelihood is a Tasmanian likelihood class, currently * LikeliTasDREAM::LikelihoodGaussIsotropic and * LikeliTasDREAM::LikelihoodGaussAnisotropic. * * \param likely is the output likelihood, it will be overwritten with the one send. * \param source is the rank of the process in the MPI comm that issued the send command. * \param tag is the tag used in the MPI send command. * \param comm is the MPI comm where the source and destination reside. * \param status is the status of the MPI_Recv() command. * * \return the error code of the MPI_Recv() command. * * \b Note: see TasDREAM::MPILikelihoodSend(). */ template int MPILikelihoodRecv(Likelihood &likely, int source, int tag, MPI_Comm comm, MPI_Status *status = MPI_STATUS_IGNORE){ MPI_Status internal_status; if (status == MPI_STATUS_IGNORE) status = &internal_status; int short_data_size; MPI_Probe(source, tag, comm, status); MPI_Get_count(status, MPI_LONG_DOUBLE, &short_data_size); size_t data_size = TasGrid::Utils::size_mult(short_data_size, 16); std::vector buff(data_size); auto result = MPI_Recv(buff.data(), (int) (data_size / 16), MPI_LONG_DOUBLE, source, tag, comm, status); TasGrid::VectorToStreamBuffer data_buffer(buff); // do not modify buff after this point std::istream is(&data_buffer); likely.read(is); return result; } /*! * \ingroup TasmanianAddonsMPIDREAMSend * \brief Split the likelihood across the comm where each rank receives an equal portion of the total outputs. * * Splits both the data and the variance across a comm. * * \b Note: this does not use MPI_Scatter(), instead it makes multiple calls to MPILikelihoodSend() and MPILikelihoodRecv(). * * \tparam Likelihood is a Tasmanian likelihood class, currently * LikeliTasDREAM::LikelihoodGaussIsotropic and * LikeliTasDREAM::LikelihoodGaussAnisotropic. * * \param source likelihood located on the \b root rank is to be distributed across, * for all other ranks the source will not be referenced. * \param destination is the likelihood where the local portion of the scatter will be stored, * the existing likelihood will be overwritten. * If the \b source outputs are less than the number of \b comm ranks, * then some of the destination likelihoods will be empty. * \param root is the rank that will hold the source likelihood. * \param tag same as in TasGrid::MPILikelihoodSend(). * \param comm is the MPI comm of all process that need to share a portion of the grid. * * \b Note: see TasGrid::MPIGridScatterOutputs() for the way the outputs will be distributed. */ template int MPILikelihoodScatter(Likelihood const &source, Likelihood &destination, int root, int tag, MPI_Comm comm){ int me = TasGrid::getMPIRank(comm); // my rank within the comm if (me == root){ // splitting and sending the grid int num_ranks; MPI_Comm_size(comm, &num_ranks); int num_effective_ranks = std::min(num_ranks, source.getNumOutputs()); int stride = source.getNumOutputs() / num_effective_ranks; int extras = source.getNumOutputs() % num_effective_ranks; // return the starting offset for the given rank auto offset = [&](int rank)->int{ return rank * stride + std::min(rank, extras); }; for(int rank=0; rank>{ public: //! \brief Make a stream-buffer from the \b data vector. VectorToStreamBuffer(std::vector &data){ setg(&*data.begin(), data.data(), &*data.end()); } }; /*! * \internal * \ingroup TasmanianAddonsMPIGridSend * \brief Utility to return the rank within the given comm. * * \endinternal */ inline int getMPIRank(MPI_Comm comm){ int rank; MPI_Comm_rank(comm, &rank); return rank; } /*! * \ingroup TasmanianAddonsMPIGridSend * \brief Send a grid to another process in the MPI comm. * * Send the grid to the destination rank across an MPI comm. * The grid is frist writtein to a stream in either binary or ASCII * format and then send with a single MPI_Send() call. * Binary results in smaller messages and less computational overhead; * thus, ASCII is provided mostly for debugging purposes. * * \tparam binary defines whether to use binary (\b true) or ASCII (\b false) mode. * Recommended use with constexpr constant TasGrid::mode_binary * and TasGrid::mode_ascii. * * \param grid is the grid to send. * \param destination is the rank of the recipient MPI process. * \param tag is the tag to use for the MPI message. * \param comm is the MPI comm where the source and destination reside. * * \return the error code of the MPI_Send() command. * * \b Note: this call must be mirrored by TasGrid::MPIGridRecv() on the * destination process. * * Example usage, process 0 creates a grid and sends it to process 1: * \code * int me, tag = 0; * MPI_Comm_rank(MPI_COMM_WORLD, &me); * MPI_Status status; * TasGrid::TasmanianSparseGrid grid; * if (me == 0) grid.makeGlobalGrid(3, 4, 5, TasGrid::type_level, TasGrid::rule_clenshawcurtis); * if (me == 0) MPIGridSend(grid, 1, tag, MPI_COMM_WORLD); * else if (me == 1) MPIGridRecv(grid, 0, tag, MPI_COMM_WORLD, &status); * // at this line, process 1 has a grid equivalent to that of process 0 * // processes with rank 2 and above do nothing, i.e., they have an empty grid * \endcode */ template int MPIGridSend(TasmanianSparseGrid const &grid, int destination, int tag, MPI_Comm comm){ std::stringstream ss; grid.write(ss, binary); while(ss.str().size() % 16 != 0) ss << " "; return MPI_Send(ss.str().c_str(), (int) (ss.str().size() / 16), MPI_LONG_DOUBLE, destination, tag, comm); } /*! * \ingroup TasmanianAddonsMPIGridSend * \brief Receive a grid from another process in the MPI comm. * * Receive a grid that has been send with TasGrid::MPIGridSend(). * This call intercepts both messages and compiles them into a sparse grid object. * * \tparam binary defines whether to use binary (\b true) or ASCII (\b false) mode. * Recommended use with constexpr constant TasGrid::mode_binary * and TasGrid::mode_ascii. * * \param grid is the output grid, it will be overwritten with grid send by * the source rank similar to TasGrid::TasmanianSparseGrid::read(). * \param source is the rank of the process in the MPI comm that issued the send command. * \param tag is the tag used in the MPI send command. * \param comm is the MPI comm where the source and destination reside. * \param status is the status of the MPI_Recv() command. * * \return the error code of the MPI_Recv() command. */ template int MPIGridRecv(TasmanianSparseGrid &grid, int source, int tag, MPI_Comm comm, MPI_Status *status = MPI_STATUS_IGNORE){ MPI_Status internal_status; if (status == MPI_STATUS_IGNORE) status = &internal_status; int short_data_size; MPI_Probe(source, tag, comm, status); MPI_Get_count(status, MPI_LONG_DOUBLE, &short_data_size); size_t data_size = Utils::size_mult(short_data_size, 16); std::vector buff(data_size); auto result = MPI_Recv(buff.data(), (int) (data_size / 16), MPI_LONG_DOUBLE, source, tag, comm, status); VectorToStreamBuffer data_buffer(buff); // do not modify buff after this point std::istream is(&data_buffer); grid.read(is, binary); return result; } /*! * \ingroup TasmanianAddonsMPIGridSend * \brief Broadcast a grid to all processes in an MPI comm. * * Make all \b grid variables for all process in the \b comm match the grid * on the \b root process. * This call uses two MPI_Bcast() calls, the grid size (in memory units) * and the actual grid data. * The transfer can be done in either binary or ASCII format, but binary results * in smaller messages and less computational overhead; * thus, ASCII is provided mostly for debugging purposes. * * \tparam binary defines whether to use binary (\b true) or ASCII (\b false) mode. * Recommended use with constexpr constant TasGrid::mode_binary * and TasGrid::mode_ascii. * * \param grid is the grid to broadcast across the MPI comm, the grid on the \b root * process will not be modified (i.e., treat as const), * in all other cases, the grid will be overwritten similar to * the TasGrid::TasmanianSparseGrid::read(). * \param root is the process that holds the data that needs to be send across. * \param comm is the MPI comm of all process that need to share the grid. * * \return the error code of the fist failed MPI_Bcast() command * (corresponding to either the size of the data message), * if MPI_SUCCESS is returned then both messages were successful. * * Example usage, process 0 reads a grid from a file and sends it to all processes: * \code * int me; * MPI_Comm_rank(MPI_COMM_WORLD, &me); * auto grid = (me == 0) ? TasGrid::readGrid("foo") : TasGrid::TasmanianSparseGrid(); * MPIGridBcast(grid, 0, MPI_COMM_WORLD); * // at this line, every process has the same grid as if they all read it from "foo" * \endcode */ template int MPIGridBcast(TasmanianSparseGrid &grid, int root, MPI_Comm comm){ int me = getMPIRank(comm); // my rank within the comm if (me == root){ // sends the grid std::stringstream ss; grid.write(ss, binary); while(ss.str().size() % 16 != 0) ss << " "; // pad with empty chars to align to 16 bytes, i.e., long double unsigned long long data_size = (unsigned long long) ss.str().size(); auto result = MPI_Bcast(&data_size, 1, MPI_UNSIGNED_LONG_LONG, me, comm); if (result != MPI_SUCCESS) return result; return MPI_Bcast(const_cast(ss.str().c_str()), (int) (data_size / 16), MPI_LONG_DOUBLE, me, comm); // Bcast root does not modify the buffer, this is const-correct }else{ // receives the grid unsigned long long data_size; auto result = MPI_Bcast(&data_size, 1, MPI_UNSIGNED_LONG_LONG, root, comm); if (result != MPI_SUCCESS) return result; std::vector buff((size_t) data_size); result = MPI_Bcast(buff.data(), (int) (buff.size() / 16), MPI_LONG_DOUBLE, root, comm); VectorToStreamBuffer data_buffer(buff); // do not modify buff after this point std::istream is(&data_buffer); grid.read(is, binary); return result; } } /*! * \ingroup TasmanianAddonsMPIGridSend * \brief Split the grid across the comm where each rank receives an equal portion of the total outputs. * * Split the grid across the ranks in the comm so that each rank receives a grid with the same type, rule, * points, etc., but with a subset of the total outputs. The distribution is as close to even as possible, * if there are less outputs than ranks, some ranks will receive an empty grid. * * \b Note: this does not use MPI_Scatter(), instead it makes multiple calls to MPIGridSend() and MPIGridRecv(). * * \tparam binary defines whether to use binary (\b true) or ASCII (\b false) mode, see TasGrid::MPIGridSend(). * * \param source grid located on the \b root rank is the grid to be distributed across, * for all other ranks the source will not be referenced. * \param destination is the grid where the local portion of the scatter will be stored, * the existing grid will be overwritten. * If the \b source outputs are less than the number of \b comm ranks, * then some of the destination grids will be empty. * \param root is the rank that will hold the source sparse grid. * \param tag same as in TasGrid::MPIGridSend(). * \param comm is the MPI comm of all process that need to share a portion of the grid. * * Example usage, rank 0 creates a large grid and scatters is across comm: * \code * int me; * MPI_Comm_rank(MPI_COMM_WORLD, &me); * auto source = (me == 0) ? TasGrid::readGrid("grid_with_many_outputs") : TasGrid::TasmanianSparseGrid(); * TasGrid::TasmanianSparseGrid grid; * MPIGridScatterOutputs(source, grid, 0, 1, 2, comm); * // at this line, every process has a portion of the source at grid * // if the comm has 3 ranks, * // then 7 outputs will be split into 3 2 2 * // and 2 outputs will become 1 1 empty * \endcode */ template int MPIGridScatterOutputs(TasmanianSparseGrid const &source, TasmanianSparseGrid &destination, int root, int tag, MPI_Comm comm){ int me = getMPIRank(comm); // my rank within the comm if (me == root){ // splitting and sending the grid int num_ranks; MPI_Comm_size(comm, &num_ranks); int num_effective_ranks = std::min(num_ranks, source.getNumOutputs()); int stride = source.getNumOutputs() / num_effective_ranks; int extras = source.getNumOutputs() % num_effective_ranks; // return the starting offset for the given rank auto offset = [&](int rank)->int{ return rank * stride + std::min(rank, extras); }; for(int rank=0; rank(copyGrid(source, offset(rank), offset(rank+1)) , rank, tag, comm); if (result != MPI_SUCCESS) return result; } } for(int rank=num_effective_ranks; rank(makeEmpty() , rank, tag, comm); if (result != MPI_SUCCESS) return result; } } return MPI_SUCCESS; // if we got here, all was successful }else{ // receiving a grid return MPIGridRecv(destination, root, tag, comm); } } } #endif // Tasmanian_ENABLE_MPI #endif TASMANIAN-8.1/CHANGELOG.md000066400000000000000000000323371470551176200145260ustar00rootroot00000000000000Changelog for version 8.1 -------------- * added support for Apple silicon M chips * python required some work-arounds and bug-fixes, C++ was good before * added more multicore cpu support * parallelized curved tensor selection and large beta, e.g., ipcurved * parallelized setting surplus refinement * compatibility with gcc parallel STL algorithms * implemented a new algorithm for global sparse Kronecker * significant speedup when loading needed values * dropped support for defunct python 2 * wasn't tested before and it was partially or fully broken already Changelog for version 8.0 -------------- * added option to automatically download/configure/build MAGMA * enabled with -DTasmanian_MAGMA_DOWNLOAD=ON * improved error checking for the CLI interface * affects mostly the internal structure * improved MATLAB interface * better internal filenames for the grid files * possible to interface with an external grid file * added bindings for the asynchronous (dynamic) construction * updated GPU support * OneAPI support for 2023 * CUDA 12 support * required CMake 3.19 and 3.21 when using HIP * switched to native search for CUDA mathlibs * switched to HIP as a CMake language * switched to DPC++ using clang++ with automatically added -fsycl flag Changelog for version 7.9 -------------- * new module: Tasmanian Optimization * implements Gradient Descent and Particle Swarm methods * included examples and documentation * credit goes to William Kong * added differentiation method for all sparse grid types * improved libEnsemble-Tasmanian integration * now includes the dynamic adaptive construction * migrated the tasmanian.ornl.gov page content to github * miscellaneous bug fixes and performance improvements Changelog for version 7.7 -------------- * added new method for constructing quadrature rules with negative weight functions * the weight function needs to be bounded from below * the methods are added to the Addons module under the Exotic Quadrature name * credit goes to William Kong * stabilized the DPC++ backend and improved the oneMKL compatibility * cleaned the build system and improved the way the dependencies are handled * stabilized the Fortrain 2003 interface to cover all Sparse Grid functionality * GPU and MPI methods are now fully supported through Fortran 2003 * added Fortran 2003 methods for complex numbers for Fourier grids * the old Fortran 90/95 interface is now deprecated * improved the grid compression methods * now can remove points by keeping a specific number of points/basis-functions * moved the post-install testing to CMake * simplifies the spack testing for the E4S compatibility * improved the libEnsemble-Tasmanian integration, see the documentation * improved the logic for accepting external handles and queues for all GPUs * deprecated the simple install script, use CMake directly Changelog for version 7.5 -------------- * added DPC++ backend using oneMKL * added both kernels and calls to BLAS/LAPACK methods * the kernels for the global grids is missing atomics (currently very slow) * updated Rocm interface * using the Rocm OpenMP implementation in libiomp5.so and libomp.so * added github CI covering a MacOSX build and basic Ubuntu build * credit goes to Viktor Reshniak * extended the Fortrain 2003 methods * added functions, e.g., returnPoints() as members to TasmanianSparseGrid * added MPI methods to the Fortain interface * updates to the GNU Make build system * removed Fortran from the GNU Make build system, use CMake * the added complexity to the SWIG build system is too much to maintain * GNU Make now defaults to Python 3, removed the make python3 target Changelog for version 7.3 -------------- * added AMD HIP/ROCm backend * all CUDA capabilities have an AMD HIP/ROCm equivalent * this includes MAGMA-HIP capabilities * capabilities are accessed with accel_gpu_cuda and accel_gpu_cublas * removed the XSDK names for options * the XSDK requirement was alleviated due to spack * CMake now builds only one type of library shared or static * matlab interface works well with shared libs thanks to rpaths * magma search is simpler looking for either shared or static libs * ::shared and ::static targets are deprecated Changelog for version 7.1 -------------- * the Python pip installer can now enable CUDA, MAGMA, MPI, etc. * requires setting environment variables * the Python pip installer now handles dependencies automatically * requires an up-to-date version of pip * added the API to manually set the CUDA handles * manual handles can be set for cuBlas, cuSparse and cuSolverDn * new addon method for constructing a surrogate from unstructured data * utilizes QR factorization from cuSolver and MAGMA * using out-of-core implementation within MAGMA * an LAPACK implementation is required for the BLAS option * BLAS and LAPACK are packaged together in all tested libraries * added Swig generated Fortran 2003 interface * naming conventions and objects mimic C++, similar to python * split the Tasmanian::Tasmanian and Tasmanian::Fortran targets * also added Tasmanian::Fortran::shared and Tasmanian::Fortran::static * added mixed-precision templates for * `evaluateBatchGPU()` and `evaluateHierarchicalFunctionsGPU()` * `evaluateBatch()` when the acceleration mode is cuda or magma Changelog for version 7.0 -------------- * improved MPI capability, see the updated documentation * fully automated distributed adaptive sparse grid construction * new module "Tasmanian Addons" consisting of miscellaneous templates * algorithms for automated sampling from a lambda model * use through the master target and header, cannot be used independently * new Tasmanian CMake master targets that handle all modules * now available Tasmanian::shared and Tasmanian::static * also Tasmanian::Tasmanian will always point to an available target * added Tasmanian::tasgrid imported executable target * new Tasmanian master Python module: `import Tasmanian` * the python changes are backwards compatible, the old module is still there * the sparse grid class can be called with `grid = Tasmanian.SparseGrid()` * the DREAM binding is available through `Tasmanian.DREAM` * new Tasmanian master header to add all modules: Tasmanian.hpp * new dynamic construction algorithms have been added * removed the need for blocking between refinement iterations * Tasmanian can accept data one-point at a time * new candidate points can be requested at any time * candidate points for dynamic construction are weighted by "importance" * the dynamic construction process is available through C++ and Python interfaces * modernized C++ compatibility * see the updated DREAM api notes * TasmanianSparseGrid has move and copy constructors and `operator=` overloads * Tasmanian C++ API no-longer returns raw-pointers, only STL containers * **broke backward api** affects mostly get points and weights * externally allocated raw-pointers are still accepted and used by C/Python/Fortran APIs * updated the Fortran interface, the library no longer has a global state * replaced the integer grid-ids with a derived type(TasmanianSparseGrid) * grid variables now require tsgAllocateGrid(grid) and tsgDeallocateGrid(grid) * tsgAllocateGrid() is now thread safe (when called on different grid variables) * no other changes appear on the front-end, see the Fortran examples * improved the `add_subdirectory()` capability * can specify the export name used by the Tasmanian install commands * `set(Tasmanian_export_name CACHE INTERNAL "")` * `add_subdirectory( )` * `install(EXPORT ${Tasmanian_export_name} ...)` * the export name functionality is required to import the transitive dependencies * in addition, when using `add_subdirectory()`: * will not enable testing, tests are still set if enabled by the master project * will not install package-config, that is the job of the master project * will not install example CMakeLists.txt or post-install tests * (`make test_install` and examples require Tasmanian package-config) * updated the DREAM interface: * excessive polymorphism is replaced by lambdas * sampling is done by a template * can specify arbitrary domain (using lambdas) * the new API is also available though Python * Note: the old API is completely obsolete and incompatible * added Doxygen documentation (CMake option, extra pages, etc.) * improved CUDA support * added support for CUDA 10 * all grids now benefit from all acceleration modes * added `evaluateBatchGPU()` where both `x` and `y` sit on the GPU * removed the deprecated MS Windows build system with batch scripts * require cmake 3.10 or newer * removed the clumsy work-around for OpenMP on old cmake systems * removed other small legacy cmake fixes * added cuda as a cmake lang, added multiple hacks to avoid feature regression Changelog for version 6.0 -------------- * as always, a new version includes numerous bug fixes and performance enhancements * CXX standard 2011 is now required and enabled by default * required cmake 3.5 or newer (as opposed to 2.8 in version 5.1) * merged Tasmanian_ENABLE_CUBLAS option into Tasmanian_ENABLE_CUDA * the option is OFF by default * two distinct acceleration modes use this variable: `gpu-cublas` and `gpu-cuda` * added new acceleration mode `gpu-magma` that uses UTK MAGMA library (requires CUDA) * removed Tasmanian_STRICT_OPTIONS, now all options are considered strict by default * new option Tasmanian_ENABLE_RECOMMENDED * searches for OpenMP, BLAS, and Python, and enables if found * set the `-O3` flag for Debug and Release * adjusted the install script, see `./install --help` * modified install folder structure now everything sits in four places * `/bin` takes the executable files * `/lib` takes the libraries and Fortran `.mod` files * `/lib/Tasmanian` takes the cmake package-config * `/lib/PythonX.Y` takes the python module * `/include` takes the headers * `/share/Tasmanian` takes everything else * added package-config file, now it is possible to use the command ``` find_package(Tasmanian 6.0 PATHS "") # PATHS "" not needed if the install folder # is included in CMAKE_PREFIX_PATH ``` * added new grids and rules * `GridFourier` that uses trigonometric basis functions (see Manual) * `localpb` rule to local polynomial grids that favors the boundary * API change for error handling (not backward compatible) * errors in C++ now throw exceptions * `std::runtime_error` is thrown on wrong file format * `std::runtime_error` is thrown when requesting level too high * `std::invalid_argument` is thrown when calling function for wrong grid * `logstream` is no longer needed and has been removed * the error handling in the interface calls remains the same as before * updated C++ API with overloaded functions * using `std::vector` as opposed to arrays * error checking is provided based on the vector size * massive portion of the internal API has also changed * acceleration with custom CUDA kernels is now available * Sequence grids, i.e., build with `makeSequenceGrid()` * Fourier grids, i.e., build with `makeFourierGrid()` * the library is more robust when working with large data sets * number of points, outputs, or batch size is still `int` * in most cases the product (i.e., matrix size) can exceed `MAX_INT` * improved MS Windows support using cmake * recommended optimization flags are properly set (Debug and Release) * shared symbols are exported by cmake * CUDA is now supported under Windows * `getGPUName()` under Python currently does not work * the old `WindowsMake.bat` script is deprecated Changelog for version 5.1 -------------- * visit us on github.com/ORNL/TASMANIAN * added functionality to access hierarchical functions and coefficients which allows constructing model approximation from an arbitrary cloud of samples, as opposed to requiring the use of the specific points in the hypercube * added custom CUDA kernels for evaluations for LocalPolynomial grids, both sparse/dense basis of hierarchical functions and batch evaluations can be performed with the CUDA kernels for extra speed. evaluateFast for LocalPolynomial also benefits from acceleration * grids can be written/read in either binary or ascii format, MATLAB defaults to binary format now * CUDA accelerated evaluations can be triggered from MATLAB, just specify `lGrid.gpuDevice = X,` where X is a valid CUDA device run `tsgCoreTests()` to see a list of the available devices * added tsgCoreTests() script to MATLAB * added tweaks and simplifications to the build system, the main options remain the same, but check the manual for changes to the additional options * added Fortran 90/95 interface (still very EXPERIMENTAL) * significantly expanded the automated testing procedures and code coverage * numerous bug fixes and performance enhancements TASMANIAN-8.1/CMakeLists.txt000066400000000000000000000233211470551176200154460ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.19) cmake_policy(VERSION 3.19) project(Tasmanian VERSION 8.1.0 LANGUAGES CXX) set(Tasmanian_version_comment "") # e.g., " (release candidate)", " (development)", "" set(Tasmanian_license "BSD 3-Clause with UT-Battelle disclaimer") # used in some headers and python modules (only human readable) ######################################################################## # User specified options: # -D Tasmanian_ENABLE_RECOMMENDED:BOOL=OFF (includes some flags) # -D Tasmanian_ENABLE_OPENMP:BOOL=OFF (recommended) # -D Tasmanian_ENABLE_BLAS:BOOL=OFF (recommended) # -D Tasmanian_ENABLE_PYTHON:BOOL=OFF (recommended) # -D Tasmanian_ENABLE_CUDA:BOOL=OFF (stable) # -D Tasmanian_ENABLE_HIP:BOOL=OFF (stable) # -D Tasmanian_ENABLE_DPCPP:BOOL=OFF (stable) # -D Tasmanian_ENABLE_MAGMA:BOOL=OFF (stable) # -D Tasmanian_MATLAB_WORK_FOLDER:PATH="" (stable) # -D Tasmanian_ENABLE_FORTRAN:BOOL=OFF (stable) # -D Tasmanian_ENABLE_MPI:BOOL=OFF (stable) # -D Tasmanian_ENABLE_SWIG:BOOL=OFF (stable) # # Additional options: (if default test behavior is not desired) # -D Tasmanian_TESTS_OMP_NUM_THREADS:INT="sets OpenMP number of threads" # -D Tasmanian_TESTS_GPU_ID:INT="specifies which GPU to use for testing" # # Extra options: (allow for workarounds of bugs and exotic systems) # -D Tasmanian_EXTRA_LIBRARIES:STRING="appends more link libraries" # -D Tasmanian_EXTRA_INCLUDE_DIRS:LIST="appends more include paths" # -D Tasmanian_EXTRA_LINK_DIRS:PATH="appends more link paths" # # Selecting specific packages for find_package() # -D Python_ROOT_DIR:PATH # -D CMAKE_CUDA_COMPILER:PATH # -D Tasmanian_MAGMA_ROOT:PATH (or just MAGMA_ROOT) # -D MPI_CXX_COMPILER # -D MPI_Fortran_COMPILER (must be compatible with the MPI_CXX_COMPILER) # -D MPIEXEC_EXECUTABLE (must be compatible with the MPI_CXX_COMPILER) # -D SWIG_EXECUTABLE (path to swigfortran) # (note: swig may require extra includes, use Tasmanian_EXTRA_INCLUDE_DIRS) # # Directly specifying libraries and bypassing find_package() # -D BLAS_LIBRARIES # -D LAPACK_LIBRARIES # # Note: directly specifying libraries still requires the corresponding # Tasmanian_ENABLE_ option # ######################################################################## ######################################################################## # The build process follows these steps: # 1. Define all options and assign default values # 2. Perform sanity check # - resolve conflicts, e.g., Python requires shared libs # - call find_package() for options that need packages # - fail or fallback if find_package() fails for some option # - add Tasmanian_dependencies target with all TPLs # 3. Enable testing and set the master config file # 4. Add all subdirectories in the correct order # - SparseGirds, DREAM, Addons # - Interfaces: Python, Fortran, MATLAB # - master target and examples # 5. Install top level files # - add the "make test_install" target # - cmake export file # - master config file # - CMakeLists.txt for the examples (include OpenMP hack if needed) # - shell (bash) source file that defines paths # 6. Print final messages ######################################################################## option(BUILD_SHARED_LIBS "Specify shared or static libraries for Tasmanian" ON) option(Tasmanian_ENABLE_RECOMMENDED "Enable (if found) OpenMP, BLAS, and Python, also sets optimization flags" OFF) option(Tasmanian_ENABLE_OPENMP "Enable OpenMP support for Tasmanian (recommended)" OFF) option(Tasmanian_ENABLE_BLAS "Enable CPU Blas support for Tasmanian (recommended)" OFF) option(Tasmanian_ENABLE_PYTHON "Enable Python interface for Tasmanian (recommended)" OFF) option(Tasmanian_ENABLE_CUDA "Enable Nvidia CUDA kernels and libraries within Tasmanian (stable)" OFF) option(Tasmanian_ENABLE_HIP "Enable AMD HIP kernels and ROCm libraries within Tasmanian (stable)" OFF) option(Tasmanian_ENABLE_DPCPP "Enable Intel DPC++ kernels and libraries within Tasmanian (stable)" OFF) option(Tasmanian_ENABLE_MAGMA "Enable acceleration using UTK Magma library within Tasmanian (stable)" OFF) option(Tasmanian_ENABLE_FORTRAN "Enable Fortran interface for Tasmanian (stable)" OFF) option(Tasmanian_ENABLE_MPI "Enable MPI support for Tasmanian (stable)" OFF) option(Tasmanian_ENABLE_SWIG "Regenerate Fortran 2003 bindings with SWIG (developers only)" OFF) option(Tasmanian_ENABLE_DOXYGEN "Enable Doxygen documentation for Tasmanian (complete)" OFF) option(Tasmanian_ENABLE_FORTRAN90 "(deprecated, untested) Enable the old Fortran 90 interface of Tasmanian" OFF) # treat those similar to options, but give values other than ON/OFF set(Tasmanian_MATLAB_WORK_FOLDER "" CACHE PATH "Enable MATLAB interface and use the path for the MATLAB work folder (stable)") set(Tasmanian_TESTS_GPU_ID "-1" CACHE STRING "(integer) specify GPU ID for testing, -1 means running tests on all visible devices (optional)") set(Tasmanian_TESTS_OMP_NUM_THREADS "-1" CACHE STRING "(integer) specify OMP_NUM_THREADS for the tests, if less than 0, this option will be ignored (optional)") # allow an external project to specify the export variable name if (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) set(Tasmanian_export_name "Tasmanian-export") enable_testing() # Tasmanian is the main project, enable testing else() set(Tasmanian_export_name "Tasmanian-export" CACHE STRING "Specify the export variable name when merging Tasmanian into an external project") endif() if (Tasmanian_ENABLE_CUDA AND NOT DEFINED CMAKE_CUDA_ARCHITECTURES) set(CMAKE_CUDA_ARCHITECTURES "OFF" CACHE STRING "CUDA architectures to compile, e.g., -DCMAKE_CUDA_ARCHITECTURES=70;72") endif() if (Tasmanian_ENABLE_ROCM) # alias option set(Tasmanian_ENABLE_HIP ON) endif() ######################################################################## # Sanity check, xSDK compatibility, and find_package() calls are all # done in one place for consistency # after this call, every enabled option comes with proper found set of # find_package() provided libraries, includes, etc. # Also adds Tasmanian_dependencies that links to all dependencies ######################################################################## include("${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/helper_macros.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/sanity_check_and_xsdk.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/add_dependencies_target.cmake") ######################################################################## # Core project configuration, passes all options to CXX ######################################################################## configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Config/TasmanianConfig.in.hpp" "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianConfig.hpp") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianConfig.hpp" DESTINATION include PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) # configure the headers for the logs configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Tasgrid/tasgridLogs.in.hpp" "${CMAKE_CURRENT_BINARY_DIR}/configured/tasgridLogs.hpp") ######################################################################## # Setup targets # CXX subdirs have to come first, SparseGrids must precede DREAM # the Addons must come last # each sub-directory creates a set of targets and links those to # existing targets (hence the order is important) # After CXX, the interfaces Fortran, Python, MATLAB can come in any order # Finally, add the master target to link to all of the above ######################################################################## add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/SparseGrids" "${CMAKE_CURRENT_BINARY_DIR}/SparseGrids") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/DREAM" "${CMAKE_CURRENT_BINARY_DIR}/DREAM") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/Addons" "${CMAKE_CURRENT_BINARY_DIR}/Addons") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/Tasgrid/" "${CMAKE_CURRENT_BINARY_DIR}/Tasgrid") if (Tasmanian_ENABLE_FORTRAN) if (Tasmanian_ENABLE_FORTRAN90) add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/InterfaceFortran" "${CMAKE_CURRENT_BINARY_DIR}/Fortran") endif() add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/InterfaceSwig" "${CMAKE_CURRENT_BINARY_DIR}/Fortran03") endif() if (Tasmanian_ENABLE_PYTHON) add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/InterfacePython" "${CMAKE_CURRENT_BINARY_DIR}/Python") endif() if (NOT "${Tasmanian_MATLAB_WORK_FOLDER}" STREQUAL "") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/InterfaceMATLAB" "${CMAKE_CURRENT_BINARY_DIR}/MATLAB") endif() if (Tasmanian_ENABLE_DOXYGEN) add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/Doxygen" "${CMAKE_CURRENT_BINARY_DIR}/Doxygen") endif() include("${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/master_targets.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/all_examples.cmake") ######################################################################## # Tasmanian is merged into an external master project then skip the exports # The master should be responsible for post-install testing and exporting ######################################################################## if (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) include("${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/exports.cmake") endif() ######################################################################## # Setup Message ######################################################################## include("${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/setup_message.cmake") TASMANIAN-8.1/Config/000077500000000000000000000000001470551176200141125ustar00rootroot00000000000000TASMANIAN-8.1/Config/AltBuildSystems/000077500000000000000000000000001470551176200172025ustar00rootroot00000000000000TASMANIAN-8.1/Config/AltBuildSystems/HeaderConvert.py000066400000000000000000000044041470551176200223070ustar00rootroot00000000000000#!/usr/bin/env python3 # this script takes TasmanianSparseGridWrapC.cpp and parces out # all the methods, then puts them in TasmanianSparseGrid.h # methods must be defined on a single line and start with type + tsg # e.g., void tsg... or void *tsg with open("../../SparseGrids/TasmanianSparseGrid.hpp") as tsghpp: lTsgHpp = tsghpp.readlines() with open("../../SparseGrids/TasmanianSparseGridWrapC.cpp") as tsgcpp: lTsgCpp = tsgcpp.readlines() lTsgH =[] iStage = 0 for sLine in lTsgHpp: sLine = sLine.replace('\n', '') if (iStage == 0): # copyright statement lTsgH.append(sLine + "\n") if ("*/" in sLine): iStage = 1 elif (iStage == 1): # ifndef statement lTsgH.append("\n") lTsgH.append("#ifndef __TASMANIAN_SPARSE_GRID_H\n") lTsgH.append("#define __TASMANIAN_SPARSE_GRID_H\n") lTsgH.append("\n") lTsgH.append("// ------------ C Interface for TasmanianSparseGrid -------------- //\n") lTsgH.append("// NOTE: you need to explicitly call the constructor and destructor\n") lTsgH.append("// in all cases, void *grid is a pointer to a C++ class\n") lTsgH.append("\n") iStage = 2 iStage = 0 for sLine in lTsgCpp: if (iStage == 0): if ('extern "C"' in sLine): iStage = 1 elif (iStage == 1): # if this is the definition of a function if (sLine.startswith("//")): lTsgH.append(sLine) elif (("void* tsg" in sLine) or ("void *tsg" in sLine) or ("void * tsg" in sLine) or ("void tsg" in sLine) or ("int* tsg" in sLine) or ("int *tsg" in sLine) or ("int * tsg" in sLine) or ("int tsg" in sLine) or ("double* tsg" in sLine) or ("double *tsg" in sLine) or ("double * tsg" in sLine) or ("double tsg" in sLine) or ("char* tsg" in sLine) or ("char *tsg" in sLine) or ("char * tsg" in sLine) or ("char tsg" in sLine)): sDef = sLine.split("{")[0] + ";" lTsgH.append(sDef + "\n") #print(sDef) lTsgH.append("\n") lTsgH.append("#endif\n") with open("TasmanianSparseGrid.h", 'w') as outp: outp.writelines(lTsgH) TASMANIAN-8.1/Config/AltBuildSystems/TasmanianConfig.hpp000066400000000000000000000053051470551176200227570ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_CONFIG_HPP #define __TASMANIAN_CONFIG_HPP #define TASMANIAN_VERSION_MAJOR 8 #define TASMANIAN_VERSION_MINOR 1 #define TASMANIAN_VERSION_STRING "8.1" #define TASMANIAN_LICENSE "BSD 3-Clause with UT-Battelle disclaimer" #define TASMANIAN_GIT_COMMIT_HASH "Tasmanian git hash is not available here" #define TASMANIAN_CXX_FLAGS "Not available in simple GNU Make mode" #endif TASMANIAN-8.1/Config/AltBuildSystems/testConfigureData.py000066400000000000000000000010531470551176200231660ustar00rootroot00000000000000######################################################################## # Pre-configured for GNU Make. # The information here will be omnipresent throughout the testing # environment, which will reduce the need for configuring. ######################################################################## bEnableSyncTests = True sLibPath = "./libtasmaniansparsegrid.so" iGPUID = -1 # not used by the GNU Make bHasBlas = False bHasCuBlas = False bHasCuda = False bHasSycl = False bUsingMSVC = False sGaussPattersonTableFile = "GaussPattersonRule.table" TASMANIAN-8.1/Config/AltBuildSystems/tsgGetPaths.m000066400000000000000000000007601470551176200216200ustar00rootroot00000000000000function [sFiles, sTasGrid] = tsgGetPaths() % % [sFiles, sTasGrid] = tsgGetPaths() % % You should edit the following variables accordingly % sTasGrdid should be the path + executable of that tasgrid wrapper % sFile should be root of the work files directory % % it is recommended to use absolute path sTasGrid = ['ENTER THE PATH TO tasgrid EXECUTABLE']; sFiles = ['ENTER THE PATH TO MATLAB WORK FOLDER']; sTasGrid = regexprep(sTasGrid, ' ', '\\ '); sFiles = regexprep(sFiles, ' ', '\\ '); end TASMANIAN-8.1/Config/CMakeIncludes/000077500000000000000000000000001470551176200165615ustar00rootroot00000000000000TASMANIAN-8.1/Config/CMakeIncludes/CMakeLists.txt000066400000000000000000000116141470551176200213240ustar00rootroot00000000000000######################################################################## # Install Message # This is written in this CMakeLists.txt and add subdir is called last # thus, the message will appear at the very end of the install process # # Do not put any other code here, this is for human readability only ######################################################################## set(Tasmanian_post_install "--------------------------------------------------------------------------------\n\n") set(Tasmanian_post_install "${Tasmanian_post_install}Tasmanian Install Complete: Installed Version ${Tasmanian_VERSION_MAJOR}.${Tasmanian_VERSION_MINOR}${Tasmanian_version_comment}\n\n") set(Tasmanian_post_install "${Tasmanian_post_install}executable:\n tasgrid${CMAKE_EXECUTABLE_SUFFIX_CXX}\n") if (BUILD_SHARED_LIBS) set(TSGLTYPE "SHARED") else() set(TSGLTYPE "STATIC") endif() set(Tasmanian_post_install "${Tasmanian_post_install}libraries:\n") foreach(_tsgtarget Tasmanian_libsparsegrid Tasmanian_libdream Tasmanian_libfortran90 Tasmanian_libfortran03) if (TARGET ${_tsgtarget}) get_target_property(_tsgname ${_tsgtarget} OUTPUT_NAME) set(Tasmanian_post_install "${Tasmanian_post_install} ${CMAKE_${TSGLTYPE}_LIBRARY_PREFIX}${_tsgname}${CMAKE_${TSGLTYPE}_LIBRARY_SUFFIX}\n") endif() unset(_tsgname) endforeach() unset(TSGLTYPE) unset(_tsgtarget) unset(Tasmanian_fortran_target) if (Tasmanian_ENABLE_FORTRAN) set(Tasmanian_post_install "${Tasmanian_post_install}Fortran module:\n") set(Tasmanian_post_install "${Tasmanian_post_install} tasmanian.mod\n") if (Tasmanian_ENABLE_MPI) set(Tasmanian_post_install "${Tasmanian_post_install} tasmanian_mpi.mod\n") endif() if (Tasmanian_ENABLE_FORTRAN90) set(Tasmanian_post_install "${Tasmanian_post_install} tasmaniansg.mod\n") endif() endif() set(Tasmanian_post_install "${Tasmanian_post_install}\nsee the examples:\n ${Tasmanian_final_install_path}/share/Tasmanian/examples/\n\n") set(Tasmanian_post_install "${Tasmanian_post_install}bash environment setup:\n source ${Tasmanian_final_install_path}/share/Tasmanian/TasmanianENVsetup.sh\n\n") set(Tasmanian_post_install "${Tasmanian_post_install}cmake package config:\n find_package(Tasmanian ${Tasmanian_VERSION_MAJOR}.${Tasmanian_VERSION_MINOR}.${Tasmanian_VERSION_PATCH} PATHS \\\"${Tasmanian_final_install_path}/lib/\\\")\n\n") set(Tasmanian_post_install "${Tasmanian_post_install} CMake components:\n") set(Tasmanian_post_install "${Tasmanian_post_install} ${Tasmanian_components}\n") set(Tasmanian_post_install "${Tasmanian_post_install} CXX targets:\n") set(Tasmanian_post_install "${Tasmanian_post_install} Tasmanian::tasgrid (executable)\n") set(Tasmanian_post_install "${Tasmanian_post_install} Tasmanian::Tasmanian (CXX libraries)\n\n") if (Tasmanian_ENABLE_FORTRAN) set(Tasmanian_post_install "${Tasmanian_post_install} Fortran targets:\n") set(Tasmanian_post_install "${Tasmanian_post_install} Tasmanian::Fortran (Fortran libraries)\n\n") endif() set(Tasmanian_post_install "${Tasmanian_post_install} see also:\n ${Tasmanian_final_install_path}/share/Tasmanian/examples/CMakeLists.txt\n") set(Tasmanian_post_install "${Tasmanian_post_install}\n") if (Tasmanian_ENABLE_PYTHON AND ("${Tasmanian_final_install_path}" STREQUAL "${CMAKE_INSTALL_PREFIX}")) set(Tasmanian_post_install "${Tasmanian_post_install}python module path and alternatives:\n") set(Tasmanian_post_install "${Tasmanian_post_install} ${Tasmanian_python_install_path}/Tasmanian.py\n ${CMAKE_INSTALL_PREFIX}/share/Tasmanian/python/Tasmanian.py\n\n") set(Tasmanian_post_install "${Tasmanian_post_install} import sys\n") set(Tasmanian_post_install "${Tasmanian_post_install} sys.path.append(\\\"${CMAKE_INSTALL_PREFIX}/share/Tasmanian/python\\\")\n") set(Tasmanian_post_install "${Tasmanian_post_install} import Tasmanian\n\n") endif() if (NOT "${Tasmanian_MATLAB_WORK_FOLDER}" STREQUAL "") set(Tasmanian_post_install "${Tasmanian_post_install}matlab scripts location:\n ${Tasmanian_final_install_path}/share/Tasmanian/matlab/\n\n") set(Tasmanian_post_install "${Tasmanian_post_install} addpath('${Tasmanian_final_install_path}/share/Tasmanian/matlab/')\n") endif() set(Tasmanian_post_install "${Tasmanian_post_install}--------------------------------------------------------------------------------\n") string(REPLACE "\\\"" "\"" _tsg_message "${Tasmanian_post_install}") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/Tasmanian.log" "${_tsg_message}") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Tasmanian.log" DESTINATION "share/Tasmanian/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) unset(_tsg_message) install(CODE "message(\"${Tasmanian_post_install}\")") install(CODE "message(\"information stored in: ${CMAKE_INSTALL_PREFIX}/share/Tasmanian/Tasmanian.log\n\")") TASMANIAN-8.1/Config/CMakeIncludes/FindTasmanianDpcpp.cmake000066400000000000000000000050441470551176200232710ustar00rootroot00000000000000######################################################################## # FindTasmanianDpcpp.cmake module ######################################################################## # # DPC++ and SYCL compatibility # 1. Check if the compiler --version and --help return words like "sycl" and "DPC++", i.e., didn't accidentally set the compiler to g++ # 2. Use -DMKLROOT or environment MKLROOT to find both MKL and OneMKL # 3. Manually set the OpenMP flags, since CMake doesn't know the correct flags for DPC++ # 4. Print status message # # Defines Tasmanian_mklsycl variables with all the relevant variables for the dependencies # Note: the -fsycl flag is applied privately to lib-sparsegrid # Tasmanian_compiler_type(COMPILER ${CMAKE_CXX_COMPILER} SWITCH "--version" TYPE "DPC++" RESULT Tasmanian_dpcpp_compiler) Tasmanian_compiler_type(COMPILER ${CMAKE_CXX_COMPILER} SWITCH "--help" TYPE "sycl" RESULT Tasmanian_sycl_compiler) get_filename_component(Tasmanian_dpcpproot ${CMAKE_CXX_COMPILER} DIRECTORY) # convert /bin/dpcpp to /bin get_filename_component(Tasmanian_dpcpproot ${Tasmanian_dpcpproot} DIRECTORY) # convert /bin to if (NOT Tasmanian_dpcpp_compiler AND NOT Tasmanian_sycl_compiler) message(FATAL_ERROR "Tasmanian_ENABLE_DPCPP requires that the CMAKE_CXX_COMPILER is set to the Intel dpcpp compiler or a compatible sycl compiler.") endif() if (MKLROOT) set(Tasmanian_MKL_SYCL_ROOT "${MKLROOT}" CACHE PATH "The root folder for the Intel oneMKL installation") else() set(Tasmanian_MKL_SYCL_ROOT "$ENV{MKLROOT}" CACHE PATH "The root folder for the Intel oneMKL installation") endif() Tasmanian_find_libraries(REQUIRED mkl_sycl OPTIONAL mkl_intel_lp64 mkl_intel_thread mkl_core PREFIX ${Tasmanian_MKL_SYCL_ROOT} LIST mklsycl) if (Tasmanian_ENABLE_OPENMP OR Tasmanian_ENABLE_RECOMMENDED) set(OpenMP_CXX_FLAGS "-qopenmp") set(OpenMP_CXX_LIBRARY "${Tasmanian_syclomp};-pthread") set(OpenMP_CXX_LIB_NAMES "CXX") set(Tasmanian_ENABLE_OPENMP ON) endif() foreach(_tsg_intellib ${Tasmanian_mklsycl}) if (NOT _tsg_intellib) message(FATAL_ERROR "Missing a oneAPI/oneMKL library: ${_tsg_intellib}, try setting MKLROOT to the oneMKL installation path.") endif() get_filename_component(_tsg_mklsycl_rpath ${_tsg_intellib} DIRECTORY) list(APPEND Tasmanian_mklsycl_rpath "${_tsg_mklsycl_rpath}") endforeach() unset(_tsg_mklsycl_rpath) unset(_tsg_intellib) find_package_handle_standard_args(TasmanianDpcpp DEFAULT_MSG Tasmanian_mklsycl) TASMANIAN-8.1/Config/CMakeIncludes/FindTasmanianMagma.cmake000066400000000000000000000104431470551176200232440ustar00rootroot00000000000000######################################################################## # FindTasmanianMAGMA.cmake module ######################################################################## # # searches for libmagma and libmagma_sparse # and the associated include folder # uses paths defined by MAGMA_ROOT and Tasmanian_MAGMA_ROOT # Defines variables: # Tasmanian_magmalibs: list of libmagma and libmagma_sparse # Tasmanian_magma_h: path to the folder containing magma.h # Tasmanian_magma: the libmagma library # Tasmanian::MAGMA target # # Note: if using auto-build for MAGMA, then Tasmanian::MAGMA will point to the build tree # Tasmanian_magmalibs will point to the install tree if (NOT MAGMA_ROOT) set(MAGMA_ROOT "$ENV{MAGMA_ROOT}") endif() if (Tasmanian_MAGMA_DOWNLOAD) message(STATUS "Building MAGMA together with Tasmanian, will install alongside") include (FetchContent) if (Tasmanian_ENABLE_CUDA) set(MAGMA_ENABLE_CUDA ON CACHE BOOL "pass into MAGMA") if ("${CMAKE_CUDA_ARCHITECTURES}" STREQUAL "") message(WARNING "CMAKE_CUDA_ARCHITECTURES is unspecified which will cause CUDA to switch to JIT compilation, this is fine for Tasmanian; however, MAGMA contains a huge number of kernels and JIT adds minutes of startup time on program launch.") endif() else() set(MAGMA_ENABLE_HIP ON CACHE BOOL "pass into MAGMA") if ("${CMAKE_HIP_ARCHITECTURES}" STREQUAL "") message(WARNING "CMAKE_HIP_ARCHITECTURES is unspecified which will cause HIP to switch to JIT compilation, this is fine for Tasmanian; however, MAGMA contains a huge number of kernels and JIT adds minutes of startup time on program launch.") endif() endif() set(USE_FORTRAN ON CACHE BOOL "Passed into MAGMA, the MAGMA-Fortran capabilities are not used by Tasmanian.") FetchContent_Declare(TasmanianMAGMA URL "http://icl.utk.edu/projectsfiles/magma/downloads/magma-2.7.0.tar.gz" URL_HASH "SHA256=fda1cbc4607e77cacd8feb1c0f633c5826ba200a018f647f1c5436975b39fd18" DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/_magma_download/ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/_magma_download/magma PATCH_COMMAND patch CMakeLists.txt -i ${CMAKE_CURRENT_SOURCE_DIR}/Config/magma_cmake.patch ) FetchContent_MakeAvailable(TasmanianMAGMA) add_library(Tasmanian::MAGMA INTERFACE IMPORTED) target_link_libraries(Tasmanian::MAGMA INTERFACE magma magma_sparse) target_include_directories(Tasmanian::MAGMA INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/_magma_download/magma/include") target_include_directories(Tasmanian::MAGMA INTERFACE "${tasmanianmagma_BINARY_DIR}/include") if (BUILD_SHARED_LIBS) set(Tasmanian_magma "${CMAKE_INSTALL_PREFIX}/lib/libmagma.so;${CMAKE_INSTALL_PREFIX}/lib/libmagma_sparse.so;") else() set(Tasmanian_magma "${CMAKE_INSTALL_PREFIX}/lib/libmagma.a;${CMAKE_INSTALL_PREFIX}/lib/libmagma_sparse.a;") endif() set(Tasmanian_magma_h "${CMAKE_INSTALL_PREFIX}/include/") else() set(Tasmanian_MAGMA_ROOT "${MAGMA_ROOT}" CACHE PATH "The root folder for the MAGMA installation, e.g., containing lib and include folders") if (Tasmanian_MAGMA_ROOT) set(Tasmanian_magma_nodefault "NO_DEFAULT_PATH") endif() Tasmanian_find_libraries(REQUIRED magma OPTIONAL magma_sparse PREFIX ${Tasmanian_MAGMA_ROOT} LIST magmalibs ${Tasmanian_magma_nodefault}) if (Tasmanian_magma) # if the library is missing, there's no point in searching for the header Tasmanian_find_header(FILE "magma.h" RESULT magma_h ROOT ${Tasmanian_MAGMA_ROOT} HINT ${Tasmanian_magma} NO_DEFAULT_PATH) endif() add_library(Tasmanian::MAGMA INTERFACE IMPORTED) target_link_libraries(Tasmanian::MAGMA INTERFACE ${Tasmanian_magma}) target_include_directories(Tasmanian::MAGMA INTERFACE ${Tasmanian_magma_h}) endif() find_package_handle_standard_args(TasmanianMagma DEFAULT_MSG Tasmanian_magma Tasmanian_magma_h) unset(Tasmanian_magma_nodefault) unset(MAGMA_ROOT) TASMANIAN-8.1/Config/CMakeIncludes/PythonImportTest.py000066400000000000000000000004601470551176200224470ustar00rootroot00000000000000######################################################################## # simple pythons cript to check if numpy module exists ######################################################################## import numpy as np import ctypes as ct import sys a = np.array([0.0, 1.0, 2.0]) b = (ct.c_int * 3)() TASMANIAN-8.1/Config/CMakeIncludes/add_dependencies_target.cmake000066400000000000000000000105771470551176200244010ustar00rootroot00000000000000######################################################################## # Adds a target that includes all Tasmanian dependencies ######################################################################## add_library(Tasmanian_dependencies INTERFACE) if (Tasmanian_ENABLE_DPCPP) # c++14 is needed when paired with some compilers target_compile_features(Tasmanian_dependencies INTERFACE cxx_std_14) else() target_compile_features(Tasmanian_dependencies INTERFACE cxx_std_11) endif() list(APPEND Tasmanian_rpath "${Tasmanian_final_install_path}/lib") if (Tasmanian_ENABLE_OPENMP) target_link_libraries(Tasmanian_dependencies INTERFACE ${OpenMP_CXX_LIBRARIES}) Tasmanian_find_rpath(LIBRARIES ${OpenMP_CXX_LIBRARIES} LIST rpath) if (Tasmanian_ENABLE_HIP) # needs to be added to the ENV script for the post-install testing Tasmanian_find_rpath(LIBRARIES ${OpenMP_CXX_LIBRARIES} LIST hipomp_rpath) endif() else() target_link_libraries(Tasmanian_dependencies INTERFACE ${CMAKE_THREAD_LIBS_INIT}) Tasmanian_find_rpath(LIBRARIES ${CMAKE_THREAD_LIBS_INIT} LIST rpath) endif() if (Tasmanian_ENABLE_DPCPP) # must come before BLAS to pick MKL libraries target_link_libraries(Tasmanian_dependencies INTERFACE ${Tasmanian_mklsycl}) list(APPEND Tasmanian_rpath ${Tasmanian_mklsycl_rpath}) if (Tasmanian_MKL_SYCL_ROOT) target_include_directories(Tasmanian_dependencies INTERFACE ${Tasmanian_MKL_SYCL_ROOT}/include) endif() endif() if (Tasmanian_ENABLE_BLAS) target_link_libraries(Tasmanian_dependencies INTERFACE ${BLAS_LIBRARIES}) target_link_libraries(Tasmanian_dependencies INTERFACE ${LAPACK_LIBRARIES}) Tasmanian_find_rpath(LIBRARIES ${BLAS_LIBRARIES} LIST rpath) Tasmanian_find_rpath(LIBRARIES ${LAPACK_LIBRARIES} LIST rpath) endif() if (Tasmanian_ENABLE_CUDA) target_link_libraries(Tasmanian_dependencies INTERFACE CUDA::cublas CUDA::cusparse CUDA::cusolver CUDA::cudart) Tasmanian_find_rpath(TARGETS CUDA::cublas CUDA::cusparse CUDA::cusolver CUDA::cudart LIST rpath) endif() if (Tasmanian_ENABLE_HIP) if (IS_DIRECTORY /opt/rocm/llvm/lib/) list(APPEND Tasmanian_rpath /opt/rocm/llvm/lib/) endif() foreach(_tsg_rocm_dep ${Tasmanian_rocm_dependencies}) target_link_libraries(Tasmanian_dependencies INTERFACE roc::${_tsg_rocm_dep}) Tasmanian_find_rpath(INCLUDES ${_tsg_rocm_dep}_INCLUDE_DIR LIST rpath) endforeach() endif() if (Tasmanian_ENABLE_MAGMA) target_link_libraries(Tasmanian_dependencies INTERFACE Tasmanian::MAGMA) if (NOT Tasmanian_MAGMA_DOWNLOAD) Tasmanian_find_rpath(LIBRARIES ${Tasmanian_magma} LIST rpath) target_include_directories(Tasmanian_dependencies INTERFACE $) endif() endif() if (Tasmanian_ENABLE_MPI) target_link_libraries(Tasmanian_dependencies INTERFACE MPI::MPI_CXX) endif() target_include_directories(Tasmanian_dependencies INTERFACE $) target_include_directories(Tasmanian_dependencies INTERFACE $) target_include_directories(Tasmanian_dependencies INTERFACE $) target_include_directories(Tasmanian_dependencies INTERFACE $) target_include_directories(Tasmanian_dependencies INTERFACE $) # Tasmanian_EXTRA_LIBRARIES gives the user an option to force extra dependencies, # for example, on some systems (e.g., OLCF) find_package(BLAS) fails to # recognize that libacml_mp requires libgomp, so the build fails with either clang or ENABLE_OPENMP=OFF # -D Tasmanian_EXTRA_LIBRARIES=/path/to/libgomp.so circumvents the issue target_link_libraries(Tasmanian_dependencies ${Tasmanian_EXTRA_LIBRARIES}) foreach(_tsg_include ${Tasmanian_EXTRA_INCLUDE_DIRS}) target_include_directories(Tasmanian_dependencies INTERFACE $) target_include_directories(Tasmanian_dependencies INTERFACE $) endforeach() if (Tasmanian_EXTRA_CXX_FLAGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Tasmanian_EXTRA_CXX_FLAGS}") endif() install(TARGETS Tasmanian_dependencies EXPORT "${Tasmanian_export_name}") list(REMOVE_DUPLICATES Tasmanian_rpath) #message(STATUS "Tasmanian RPATH: ${Tasmanian_rpath}") TASMANIAN-8.1/Config/CMakeIncludes/all_examples.cmake000066400000000000000000000104131470551176200222300ustar00rootroot00000000000000add_executable(Tasmanian_example_sparse_grids SparseGrids/Examples/example_sparse_grids_01.cpp SparseGrids/Examples/example_sparse_grids_02.cpp SparseGrids/Examples/example_sparse_grids_03.cpp SparseGrids/Examples/example_sparse_grids_04.cpp SparseGrids/Examples/example_sparse_grids_05.cpp SparseGrids/Examples/example_sparse_grids_06.cpp SparseGrids/Examples/example_sparse_grids_07.cpp SparseGrids/Examples/example_sparse_grids_08.cpp SparseGrids/Examples/example_sparse_grids_09.cpp SparseGrids/Examples/example_sparse_grids_10.cpp SparseGrids/Examples/example_sparse_grids_11.cpp SparseGrids/Examples/example_sparse_grids.cpp) set_target_properties(Tasmanian_example_sparse_grids PROPERTIES OUTPUT_NAME "example_sparse_grids") target_link_libraries(Tasmanian_example_sparse_grids Tasmanian_master) add_executable(Tasmanian_example_dream DREAM/Examples/example_dream_01.cpp DREAM/Examples/example_dream_02.cpp DREAM/Examples/example_dream_03.cpp DREAM/Examples/example_dream_04.cpp DREAM/Examples/example_dream_05.cpp DREAM/Examples/example_dream.cpp) set_target_properties(Tasmanian_example_dream PROPERTIES OUTPUT_NAME "example_dream") target_link_libraries(Tasmanian_example_dream Tasmanian_master) add_executable(Tasmanian_example_optimization DREAM/Examples/example_optimization_01.cpp DREAM/Examples/example_optimization_02.cpp DREAM/Examples/example_optimization.cpp) set_target_properties(Tasmanian_example_optimization PROPERTIES OUTPUT_NAME "example_optimization") target_link_libraries(Tasmanian_example_optimization Tasmanian_master) if (Tasmanian_ENABLE_FORTRAN) if (Tasmanian_ENABLE_FORTRAN90) add_executable(Tasmanian_example_sparse_grids_f90 InterfaceFortran/Examples/example_sparse_grids.f90) set_target_properties(Tasmanian_example_sparse_grids_f90 PROPERTIES OUTPUT_NAME "example_sparse_grids_f90") target_link_libraries(Tasmanian_example_sparse_grids_f90 Tasmanian_libfortran90) Tasmanian_set_fortran_linker(TARGET Tasmanian_example_sparse_grids_f90) endif() # adding the Fortran 2003 examples add_executable(Tasmanian_example_sparse_grids_fortran InterfaceSwig/FortranExamples/example_sparse_grids.f90 InterfaceSwig/FortranExamples/example_sparse_grids_01.f90 InterfaceSwig/FortranExamples/example_sparse_grids_02.f90 InterfaceSwig/FortranExamples/example_sparse_grids_03.f90 InterfaceSwig/FortranExamples/example_sparse_grids_04.f90 ) set_target_properties(Tasmanian_example_sparse_grids_fortran PROPERTIES OUTPUT_NAME "example_sparse_grids_fortran") target_link_libraries(Tasmanian_example_sparse_grids_fortran Tasmanian_libfortran03) Tasmanian_set_fortran_linker(TARGET Tasmanian_example_sparse_grids_fortran) endif() get_filename_component(_tsg_cpath "${CMAKE_CURRENT_BINARY_DIR}" NAME) foreach(_tsg_example Tasmanian_example_sparse_grids Tasmanian_example_dream Tasmanian_example_sparse_grids_f90 Tasmanian_example_sparse_grids_fortran) if (TARGET ${_tsg_example}) Tasmanian_rpath_target(TARGET ${_tsg_example} USE_CURRENT COMPONENTS ${_tsg_cpath}/SparseGrids ${_tsg_cpath}/DREAM ${_tsg_cpath}/Fortran ${_tsg_cpath}/Fortran03) endif() endforeach() unset(_tsg_cpath) unset(_tsg_example) TASMANIAN-8.1/Config/CMakeIncludes/exports.cmake000066400000000000000000000112451470551176200212720ustar00rootroot00000000000000######################################################################## # Testing: post install, make test_install # checks if the executables run and if the examples compile and run ######################################################################## set(Tasmanian_langs "CXX") set(Tasmanian_compilers "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}") if (Tasmanian_ENABLE_FORTRAN) set(Tasmanian_langs "${Tasmanian_langs} Fortran") set(Tasmanian_compilers "${Tasmanian_compilers} -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER}") endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Testing/test_post_install.in.sh" "${CMAKE_CURRENT_BINARY_DIR}/test_post_install.sh" @ONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Testing/CMakeLists.test.cmake" "${CMAKE_CURRENT_BINARY_DIR}/configured/testing/CMakeLists.txt" @ONLY) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tasmanian_test_install) add_custom_target(test_install COMMAND "${CMAKE_CURRENT_BINARY_DIR}/test_post_install.sh" WORKING_DIRECTORY tasmanian_test_install) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured/testing/CMakeLists.txt" DESTINATION "share/Tasmanian/testing/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) ######################################################################## # Install exports, package-config files, and examples cmake file ######################################################################## install(EXPORT "${Tasmanian_export_name}" DESTINATION "lib/${CMAKE_PROJECT_NAME}" FILE "${CMAKE_PROJECT_NAME}.cmake") configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/Config/TasmanianConfig.in.cmake" "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianConfig.cmake" INSTALL_DESTINATION "lib/Tasmanian/") write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianConfigVersion.cmake" COMPATIBILITY AnyNewerVersion) # not sure why it is necessary to explicitly install TasmanianConfig.cmake, INSTALL_DESTINATION above doesn't work install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianConfig.cmake" DESTINATION "lib/Tasmanian/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianConfigVersion.cmake" DESTINATION "lib/Tasmanian/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) # master header Tasmanian.hpp install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/Config/Tasmanian.hpp" DESTINATION "include" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/Config/Tasmanian.h" DESTINATION "include" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) # TasmanianMake.in for GNU Make include/link get_target_property(Tasmanian_list Tasmanian_dependencies INTERFACE_LINK_LIBRARIES) foreach(Tasmanian_lib_ ${Tasmanian_list}) if (NOT TARGET ${Tasmanian_lib_}) set(Tasmanian_libs "${Tasmanian_libs} ${Tasmanian_lib_}") endif() endforeach() unset(Tasmanian_lib_) unset(Tasmanian_list) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Config/TasmanianMakefile.in" "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianMakefile.in" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianMakefile.in" DESTINATION "share/Tasmanian/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) # configure the cmake file for the examples, to be used post-install if (BUILD_SHARED_LIBS) set(Tasmanian_components " SHARED") else() set(Tasmanian_components " STATIC") endif() foreach(_comp OPENMP BLAS PYTHON CUDA HIP DPCPP MAGMA FORTRAN MPI) if (Tasmanian_ENABLE_${_comp}) set(Tasmanian_components "${Tasmanian_components} ${_comp}") endif() endforeach() unset(_comp) if (NOT "${Tasmanian_MATLAB_WORK_FOLDER}" STREQUAL "") set(Tasmanian_components "${Tasmanian_components} MATLAB") endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeLists.examples.cmake" "${CMAKE_CURRENT_BINARY_DIR}/configured/CMakeLists.txt" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured/CMakeLists.txt" DESTINATION "share/Tasmanian/examples/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) # configure environment shell script that can be sourced to set path and lib path configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Config/TasmanianENVsetup.in.sh" "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianENVsetup.sh" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianENVsetup.sh" DESTINATION "share/Tasmanian/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) TASMANIAN-8.1/Config/CMakeIncludes/helper_macros.cmake000066400000000000000000000231311470551176200224060ustar00rootroot00000000000000######################################################################## # Various CMake macros to be used by Tasmanian ######################################################################## # CMake native includes used in Tasmanian CMake scripts include(FindPackageHandleStandardArgs) include(CMakePackageConfigHelpers) # usage: Tasmanian_find_libraries(REQUIRED foo1 foo2 OPTIONAL foo3 PREFIX bar LIST saloon NO_DEFAULT_PATH) # this will search for foo1/2/3 in bar/ with NO_DEFAULT_PATH (skip if defaults are to be used) # the found libraries will be added to a list Tasmanian_saloon # the search results will be also added to cached variables Tasmanian_foo1 and Tasmanian_foo2 # that can be used to call find_package_handle_standard_args(... DEFAULT_MSG Tasmanian_foo1 Tasmanian_foo2) # the macro will not call find_package_handle_standard_args() # the optional libraries will not create cached entries and mission optional will not be added to the LIST macro(Tasmanian_find_libraries) cmake_parse_arguments(Tasmanian_findlibs "NO_DEFAULT_PATH" "PREFIX;LIST" "REQUIRED;OPTIONAL" ${ARGN}) foreach(_tsg_lib ${Tasmanian_findlibs_REQUIRED}) list(APPEND Tasmanian_findlibs_required "Tasmanian_${_tsg_lib}") endforeach() set(Tasmanian_findlibs_default "") if (${Tasmanian_findlibs_NO_DEFAULT_PATH}) set(Tasmanian_findlibs_default "NO_DEFAULT_PATH") endif() foreach(_tsg_lib ${Tasmanian_findlibs_REQUIRED} ${Tasmanian_findlibs_OPTIONAL}) find_library(Tasmanian_${_tsg_lib} ${_tsg_lib} HINTS "${Tasmanian_findlibs_PREFIX}" HINTS "${Tasmanian_findlibs_PREFIX}/lib/" HINTS "${Tasmanian_findlibs_PREFIX}/lib/intel64" HINTS "${Tasmanian_findlibs_PREFIX}/${CMAKE_LIBRARY_ARCHITECTURE}/lib/" HINTS "${Tasmanian_findlibs_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}" HINTS "${Tasmanian_findlibs_PREFIX}/lib64/" HINTS "${Tasmanian_findlibs_PREFIX}/${CMAKE_LIBRARY_ARCHITECTURE}/lib64/" HINTS "${Tasmanian_findlibs_PREFIX}/lib64/${CMAKE_LIBRARY_ARCHITECTURE}" ${Tasmanian_findlibs_default}) if (CMAKE_FIND_DEBUG_MODE) message(STATUS "Tasmanian searching library: ${_tsg_lib} => ${Tasmanian_${_tsg_lib}}") endif() list(FIND Tasmanian_findlibs_required "Tasmanian_${_tsg_lib}" Tasmanian_findlibs_is_required) if (${Tasmanian_findlibs_is_required} EQUAL -1) # not a required library if (Tasmanian_${_tsg_lib}) list(APPEND Tasmanian_${Tasmanian_findlibs_LIST} ${Tasmanian_${_tsg_lib}}) endif() unset(Tasmanian_${_tsg_lib} CACHE) else() list(APPEND Tasmanian_${Tasmanian_findlibs_LIST} ${Tasmanian_${_tsg_lib}}) endif() endforeach() foreach(_tsg_lib default required NO_DEFAULT_PATH PREFIX LIST REQUIRED OPTIONAL) # cleanup unset(Tasmanian_${_tsg_lib}) endforeach() unset(_tsg_lib) endmacro() # usage: Tasmanian_find_header(FILE foo.h RESULT foo_h ROOT bar HINT saloon NO_DEFAULT_PATH) # will search for file named foo.h and will add the folder in variable Tasmanian_foo_h # NO_DEFAULT_PATH defines whether to use NO_DEFAULT_PATH in the find_path() command # in addition to the default paths, the method will search for folders bar and bar/include # as well as saloon_dir, saloon_dir/include, saloon_dir/../include and saloon_dir/../../include # where saloon_dir is the directory of the file saloon macro(Tasmanian_find_header) cmake_parse_arguments(Tasmanian_findh "NO_DEFAULT_PATH" "FILE;ROOT;HINT;RESULT" "" ${ARGN}) if (Tasmanian_findh_HINT) get_filename_component(Tasmanian_findh_dir ${Tasmanian_findh_HINT} DIRECTORY) endif() set(Tasmanian_findh_default "") if (${Tasmanian_findh_NO_DEFAULT_PATH}) set(Tasmanian_findh_default "NO_DEFAULT_PATH") endif() find_path(Tasmanian_${Tasmanian_findh_RESULT} "${Tasmanian_findh_FILE}" HINTS "${Tasmanian_findh_ROOT}" HINTS "${Tasmanian_findh_ROOT}/include" HINTS "${Tasmanian_findh_dir}" HINTS "${Tasmanian_findh_dir}/include" HINTS "${Tasmanian_findh_dir}/../include" HINTS "${Tasmanian_findh_dir}/../../include" ${Tasmanian_findh_default}) if (CMAKE_FIND_DEBUG_MODE) message(STATUS "Tasmanian searching header: ${Tasmanian_findh_FILE} => ${Tasmanian_${Tasmanian_findh_RESULT}}") endif() foreach(_tsg_opts dir default NO_DEFAULT_PATH FILE ROOT HINT RESULT) # cleanup unset(Tasmanian_${_tsg_opts}) endforeach() unset(_tsg_opts) endmacro() # usage: Tasmanian_find_rpath(LIBRARIES ${BLAS_LIBRARIES} LIST rpath) # will find the rpaths for each library in the BLAS_LIBRARIES list # and will append the rpath to a list called Tasmanian_rpath macro(Tasmanian_find_rpath) cmake_parse_arguments(Tasmanian_findrpath "" "LIST" "LIBRARIES;TARGETS;INCLUDES" ${ARGN}) foreach(_tsg_lib ${Tasmanian_findrpath_LIBRARIES}) get_filename_component(_tsg_libpath ${_tsg_lib} DIRECTORY) list(APPEND Tasmanian_${Tasmanian_findrpath_LIST} ${_tsg_libpath}) #message(STATUS "rpath for ${_tsg_lib} => ${_tsg_libpath}") endforeach() foreach(_tsg_lib ${Tasmanian_findrpath_TARGETS}) get_property(_tsg_locatoin TARGET ${_tsg_lib} PROPERTY IMPORTED_LOCATION) if (_tsg_locatoin) get_filename_component(_tsg_libpath ${_tsg_locatoin} DIRECTORY) list(APPEND Tasmanian_${Tasmanian_findrpath_LIST} ${_tsg_libpath}) endif() unset(_tsg_locatoin) #message(STATUS "rpath for ${_tsg_lib} => ${_tsg_libpath}") endforeach() foreach(_tsg_lib ${Tasmanian_findrpath_INCLUDES}) get_filename_component(_tsg_libpath ${${_tsg_lib}} DIRECTORY) if (EXISTS "${_tsg_libpath}/lib") list(APPEND Tasmanian_${Tasmanian_findrpath_LIST} "${_tsg_libpath}/lib") endif() unset(_tsg_locatoin) #message(STATUS "rpath for ${_tsg_lib} => ${_tsg_libpath}/lib") endforeach() foreach(_tsg_lib LIST LIBRARIES TARGETS) # cleanup unset(Tasmanian_${_tsg_lib}) endforeach() unset(_tsg_lib) unset(_tsg_libpath) endmacro() # usage: Tasmanian_rpath_target(TARGET Tasmanian_libdream USE_CURRENT COMPONENTS SparseGrid) # will set the rpath for the given target and will handle the work-around for the missing libomp.so under HIP # the USE_CURRENT adds the current folder, use for executable targets # COMPONENTS lists the additional folders, e.g., DREAM needs SparseGrid and Addons needs both DREAM and SparseGrid macro(Tasmanian_rpath_target) cmake_parse_arguments(Tasmanian_rpt "USE_CURRENT" "TARGET" "COMPONENTS" ${ARGN}) if (Tasmanian_ENABLE_HIP) set(_rpt_rpath "${Tasmanian_rpath}") if (Tasmanian_rpt_USE_CURRENT) list(APPEND _rpt_rpath "${CMAKE_CURRENT_BINARY_DIR}") endif() foreach(_rpt_comp ${Tasmanian_rpt_COMPONENTS}) list(APPEND _rpt_rpath "${CMAKE_CURRENT_BINARY_DIR}/../${_rpt_comp}") endforeach() set_target_properties(${Tasmanian_rpt_TARGET} PROPERTIES BUILD_RPATH "${_rpt_rpath}") unset(_rpt_rpath) unset(_rpt_comp) endif() set_target_properties(${Tasmanian_rpt_TARGET} PROPERTIES INSTALL_RPATH "${Tasmanian_rpath}") unset(Tasmanian_rpt_TARGET) unset(Tasmanian_rpt_USE_CURRENT) unset(Tasmanian_rpt_COMPONENTS) endmacro() # usage: Tasmanian_rpath_target(TARGET Tasmanian_libdream) # must be called for every Fortran executable target to account for the missing main() when using ifort macro(Tasmanian_set_fortran_linker) cmake_parse_arguments(Tasmanian_flink "" "TARGET" "" ${ARGN}) if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") set_target_properties(${Tasmanian_flink_TARGET} PROPERTIES LINKER_LANGUAGE CXX) else() set_target_properties(${Tasmanian_flink_TARGET} PROPERTIES LINKER_LANGUAGE Fortran) endif() unset(Tasmanian_flink_TARGET) endmacro() # usage: Tasmanian_compiler_type(COMPILER ${CMAKE_CXX_COMPILER} TYPE "DPC++" RESULT Tasmanian_has_dpcpp) # checks whether the compiler called with "--version" returns a string that contains the TYPE # the result is written to the boolean variable macro(Tasmanian_compiler_type) cmake_parse_arguments(Tasmanian_ccheck "" "COMPILER;TYPE;RESULT;SWITCH" "" ${ARGN}) if (NOT Tasmanian_ccheck_SWITCH) set(Tasmanian_ccheck_SWITCH "--version") endif() execute_process(COMMAND ${Tasmanian_ccheck_COMPILER} ${Tasmanian_ccheck_SWITCH} OUTPUT_VARIABLE ${Tasmanian_ccheck_RESULT}) string(FIND "${${Tasmanian_ccheck_RESULT}}" "${Tasmanian_ccheck_TYPE}" ${Tasmanian_ccheck_RESULT}) if (NOT ${${Tasmanian_ccheck_RESULT}} LESS 0) set(${Tasmanian_ccheck_RESULT} ON) else() set(${Tasmanian_ccheck_RESULT} OFF) endif() unset(Tasmanian_ccheck_RESULT) unset(Tasmanian_ccheck_TYPE) unset(Tasmanian_ccheck_COMPILER) endmacro() # usage: Tasmanian_set_test_properties(TESTS Test1 Test2 Test3) # sets common properties for the Tasmanian tests, e.g., the OMP_NUM_THREADS variable macro(Tasmanian_set_test_properties) cmake_parse_arguments(Tasmanian_tprops "" "" "TESTS" ${ARGN}) if (Tasmanian_TESTS_OMP_NUM_THREADS GREATER 0) set_tests_properties(${Tasmanian_tprops_TESTS} PROPERTIES PROCESSORS "${Tasmanian_TESTS_OMP_NUM_THREADS}" ENVIRONMENT "OMP_NUM_THREADS=${Tasmanian_TESTS_OMP_NUM_THREADS}") endif() unset(Tasmanian_tprops_TESTS) endmacro() TASMANIAN-8.1/Config/CMakeIncludes/master_targets.cmake000066400000000000000000000030061470551176200226060ustar00rootroot00000000000000######################################################################## # adds a single mater target for all Tasmanian modules ######################################################################## # add master target add_library(Tasmanian_master INTERFACE) target_link_libraries(Tasmanian_master INTERFACE Tasmanian_addons) install(TARGETS Tasmanian_master EXPORT "${Tasmanian_export_name}") # add :: interface, useful when using with add_subdirectory() add_library(Tasmanian::Tasmanian INTERFACE IMPORTED GLOBAL) target_link_libraries(Tasmanian::Tasmanian INTERFACE Tasmanian_master) if (BUILD_SHARED_LIBS) # for backwards compatibility add_library(Tasmanian::shared INTERFACE IMPORTED GLOBAL) target_link_libraries(Tasmanian::shared INTERFACE Tasmanian_master) else() add_library(Tasmanian::static INTERFACE IMPORTED GLOBAL) target_link_libraries(Tasmanian::static INTERFACE Tasmanian_master) endif() if (Tasmanian_ENABLE_FORTRAN) add_library(Tasmanian::Fortran INTERFACE IMPORTED GLOBAL) target_link_libraries(Tasmanian::Fortran INTERFACE Tasmanian_libfortran90) target_link_libraries(Tasmanian::Fortran INTERFACE Tasmanian_libfortran03) if (Tasmanian_ENABLE_MPI) target_link_libraries(Tasmanian::Fortran INTERFACE Tasmanian_libfortranmpi03) endif() endif() # add executable that has the sole purpose of testing the master target add_executable(tasmanian_version "${CMAKE_CURRENT_SOURCE_DIR}/Testing/tasmanian_version.cpp") target_link_libraries(tasmanian_version Tasmanian::Tasmanian) TASMANIAN-8.1/Config/CMakeIncludes/sanity_check_and_xsdk.cmake000066400000000000000000000264121470551176200241070ustar00rootroot00000000000000######################################################################## # sanity check and xSDK compatibility ######################################################################## if ((NOT DEFINED CMAKE_BUILD_TYPE) OR (NOT CMAKE_BUILD_TYPE)) set(CMAKE_BUILD_TYPE Debug) endif() # get extra options from the ENV variables (pip-installer) if (SKBUILD) if ("$ENV{Tasmanian_ENABLE_RECOMMENDED}" STREQUAL "OFF") set(Tasmanian_ENABLE_RECOMMENDED OFF) endif() if (NOT "$ENV{Tasmanian_ENABLE_BLAS}" STREQUAL "") set(Tasmanian_ENABLE_BLAS ON) set(BLAS_LIBRARIES "$ENV{Tasmanian_ENABLE_BLAS}") set(LAPACK_LIBRARIES "$ENV{Tasmanian_ENABLE_BLAS}") endif() if (NOT "$ENV{Tasmanian_ENABLE_CUDA}" STREQUAL "") set(Tasmanian_ENABLE_CUDA ON) set(CMAKE_CUDA_COMPILER "$ENV{Tasmanian_ENABLE_CUDA}") endif() if (NOT "$ENV{Tasmanian_ENABLE_HIP}" STREQUAL "" OR NOT "$ENV{Tasmanian_ENABLE_ROCM}" STREQUAL "") set(Tasmanian_ENABLE_HIP ON) set(Tasmanian_ENABLE_ROCM "$ENV{Tasmanian_ENABLE_ROCM}") endif() if (NOT "$ENV{Tasmanian_ENABLE_DPCPP}" STREQUAL "") set(Tasmanian_ENABLE_DPCPP ON) set(CMAKE_CXX_COMPILER "$ENV{Tasmanian_ENABLE_DPCPP}") endif() if (NOT "$ENV{Tasmanian_ENABLE_MAGMA}" STREQUAL "") set(Tasmanian_ENABLE_MAGMA ON) set(MAGMA_ROOT "$ENV{Tasmanian_ENABLE_MAGMA}") endif() if (NOT "$ENV{Tasmanian_MAGMA_DOWNLOAD}" STREQUAL "") set(Tasmanian_MAGMA_DOWNLOAD ON) endif() if (NOT "$ENV{Tasmanian_ENABLE_MPI}" STREQUAL "") set(Tasmanian_ENABLE_MPI ON) set(MPI_CXX_COMPILER "$ENV{Tasmanian_ENABLE_MPI}") endif() if (NOT "$ENV{Tasmanian_MATLAB_WORK_FOLDER}" STREQUAL "") set(Tasmanian_MATLAB_WORK_FOLDER "$ENV{Tasmanian_MATLAB_WORK_FOLDER}") endif() endif() # check for Fortran, note that enable_language always gives FATAL_ERROR if the compiler is missing if (Tasmanian_ENABLE_FORTRAN) enable_language(Fortran) # check old and new Fortran compilers Tasmanian_compiler_type(COMPILER ${CMAKE_Fortran_COMPILER} TYPE "ifort" RESULT Tasmanian_ifort_compiler) Tasmanian_compiler_type(COMPILER ${CMAKE_Fortran_COMPILER} TYPE "ifx" RESULT Tasmanian_ifx_compiler) if (Tasmanian_ifort_compiler OR Tasmanian_ifx_compiler) set(Tasmanian_ifort_compiler ON) endif() endif() # swig requires Fortran and cannot handle both types of libs if (Tasmanian_ENABLE_SWIG AND NOT Tasmanian_ENABLE_FORTRAN) message(FATAL_ERROR "Tasmanian_ENABLE_SWIG=ON requires Tasmanian_ENABLE_FORTRAN=ON") endif() if (Tasmanian_ENABLE_FORTRAN90 AND NOT Tasmanian_ENABLE_FORTRAN) message(FATAL_ERROR "Tasmanian_ENABLE_FORTRAN90=ON requires Tasmanian_ENABLE_FORTRAN=ON") endif() # OpenMP setup if ((Tasmanian_ENABLE_OPENMP OR Tasmanian_ENABLE_RECOMMENDED) AND NOT Tasmanian_ENABLE_DPCPP) if (Tasmanian_ENABLE_OPENMP) find_package(OpenMP REQUIRED) # OpenMP requested explicitly, require regardless of ENABLE_RECOMMENDED else() find_package(OpenMP) set(Tasmanian_ENABLE_OPENMP ${OPENMP_CXX_FOUND}) # set ENABLE_OPENMP if OpenMP_CXX_FOUND endif() endif() # multi-threading is required by the Addons module even if OpenMP is not enabled if (NOT Tasmanian_ENABLE_OPENMP) find_package(Threads REQUIRED) endif() # check for BLAS if (Tasmanian_ENABLE_BLAS OR Tasmanian_ENABLE_RECOMMENDED) include(CheckLibraryExists) if (NOT DEFINED BLAS_LIBRARIES) # user defined BLAS libraries are an XSDK requirement if (Tasmanian_ENABLE_BLAS) find_package(BLAS REQUIRED) # if BLAS enabled explicitly, require find_package(LAPACK REQUIRED) else() find_package(BLAS) find_package(LAPACK) if (BLAS_FOUND AND LAPACK_FOUND) set(Tasmanian_ENABLE_BLAS ON) else() set(Tasmanian_ENABLE_BLAS OFF) endif() endif() endif() set(CMAKE_REQUIRED_QUIET ON) foreach(_tsglib ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES}) check_library_exists(${_tsglib} zgelq_ "" _tsgfound) if (_tsgfound) set(Tasmanian_BLAS_HAS_ZGELQ ON) endif() unset(_tsgfound CACHE) endforeach() unset(_tsglib) unset(_tsgfound) if (Tasmanian_BLAS_HAS_ZGELQ) message(STATUS "Checking for LAPACK LQ factorization: found") else() message(STATUS "Checking for LAPACK LQ factorization: not found (using QR instead)") endif() endif() # Python module requires a shared library if (Tasmanian_ENABLE_PYTHON AND NOT BUILD_SHARED_LIBS) message(FATAL_ERROR "BUILD_SHARED_LIBS is OFF, but shared libraries are required by the Tasmanian Python module") endif() # Python setup, look for python if (Tasmanian_ENABLE_PYTHON OR (Tasmanian_ENABLE_RECOMMENDED AND BUILD_SHARED_LIBS)) find_package(Python 3.0 COMPONENTS Interpreter) if (Python_FOUND) # manually test for NumPy, the cmake native lookup for NumPy is not reliable when using non-native cmake in Ubuntu # the search itself is designed to find the NumPy headers for compiling with C and not just the import numpy execute_process(COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/PythonImportTest.py" RESULT_VARIABLE Tasmanian_python_has_numpy) if (NOT "${Tasmanian_python_has_numpy}" STREQUAL "0") # exit code 0 means all OK if (Tasmanian_ENABLE_PYTHON) message(FATAL_ERROR "CMake found Python, but simple 'import numpy' failed. Probably missing numpy module.") endif() else() # found python and numpy set(Tasmanian_ENABLE_PYTHON ON) endif() else() if (Tasmanian_ENABLE_PYTHON) message(FATAL_ERROR "CMake could not find Python") endif() endif() endif() # CUDA and HIP cannot be used simultaneously if ((Tasmanian_ENABLE_CUDA AND Tasmanian_ENABLE_HIP) OR (Tasmanian_ENABLE_CUDA AND Tasmanian_ENABLE_DPCPP) OR (Tasmanian_ENABLE_DPCPP AND Tasmanian_ENABLE_HIP)) message(FATAL_ERROR "Tasmanian can only use one GPU backend at a time, pick either CUDA, HIP or DPCPP") endif() # using the Tasmanian find modules requires the path if (Tasmanian_ENABLE_DPCPP OR Tasmanian_ENABLE_MAGMA) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/") endif() # Tasmanian_ENABLE_CUDA support if (Tasmanian_ENABLE_CUDA) enable_language(CUDA) find_package(CUDAToolkit REQUIRED) endif() # AMD HIP support if (Tasmanian_ENABLE_HIP) if (CMAKE_VERSION VERSION_LESS 3.21) message(FATAL_ERROR "Tasmanian HIP/ROCm GPU backend requires CMake version 3.21 or newer") endif() if (ROCM_PATH) list (APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/hip ${ROCM_PATH}) elseif (DEFINED ENV{ROCM_PATH}) list (APPEND CMAKE_PREFIX_PATH ENV{ROCM_PATH}/hip ENV{ROCM_PATH}) elseif (IS_DIRECTORY /opt/rocm) list (APPEND CMAKE_PREFIX_PATH /opt/rocm/hip /opt/rocm) endif() if (IS_DIRECTORY Tasmanian_ENABLE_ROCM) list (APPEND CMAKE_PREFIX_PATH ${Tasmanian_ENABLE_ROCM}) endif() enable_language(HIP) set(Tasmanian_rocm_dependencies "rocblas;rocsparse;rocsolver") if (Tasmanian_ENABLE_MAGMA) list(APPEND Tasmanian_rocm_dependencies "hipblas;hipsparse") endif() foreach(_tsg_roclib ${Tasmanian_rocm_dependencies}) find_package(${_tsg_roclib} REQUIRED) endforeach() endif() # Intel DPC++ support if (Tasmanian_ENABLE_DPCPP) find_package(TasmanianDpcpp REQUIRED) if (NOT Tasmanian_ENABLE_BLAS) message(FATAL_ERROR "Tasmanian DPC++ capabilities require Tasmanian_ENABLE_BLAS which must be set to MKL") endif() endif() # check for MAGMA if (Tasmanian_ENABLE_MAGMA) if (NOT Tasmanian_ENABLE_CUDA AND NOT Tasmanian_ENABLE_HIP) message(FATAL_ERROR "Tasmanian uses the GPU capabilities of MAGMA thus either CUDA or HIP must be enabled too.") endif() find_package(TasmanianMagma REQUIRED) endif() # check for MPI if (Tasmanian_ENABLE_MPI) find_package(MPI REQUIRED) endif() # check if building with Python scikit-build, i.e., pip install if (SKBUILD) # scikit build compiles and install in one place, then moves the files to a new location # Tasmanian needs the final install path so scripts can find the libraries and # the libraries can find each-other with rpath without LD_LIBRARY_PATH set(Tasmanian_final_install_path "${Tasmanian_python_pip_final}") else() set(Tasmanian_final_install_path "${CMAKE_INSTALL_PREFIX}") endif() ######################################################################## # Recommended compiler flags: Intel hasn't been tested in a while ######################################################################## if (Tasmanian_ENABLE_RECOMMENDED) if ((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") OR (${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel")) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O3") # there is no point in making a slow debug if (Tasmanian_ENABLE_FORTRAN) set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS} -O3") endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(CMAKE_CXX_FLAGS_RELEASE "/MD /Ox /DNDEBUG ${OpenMP_CXX_FLAGS}") # cmake overwrites flags a lot, careful how you set those set(CMAKE_CXX_FLAGS_DEBUG "/MDd /Ox ${OpenMP_CXX_FLAGS}") endif() endif() ######################################################################## # Check for the git commit hash, if using a git repo ######################################################################## if ("${Tasmanian_version_comment}" STREQUAL "") set(Tasmanian_git_hash "Release ${Tasmanian_VERSION_MAJOR}.${Tasmanian_VERSION_MINOR}") elseif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") # this is a git repo find_package(Git) # do not set the hash if git is missing or # if we are generating files for simple GNU Make compatibility if (Git_FOUND) execute_process(COMMAND ${GIT_EXECUTABLE} log --pretty=format:%H -n 1 WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE Tasmanian_git_hash) endif() endif() if (NOT Tasmanian_git_hash) # if not in a git repo, or there is no git executable, or if generating GNU Make files set(Tasmanian_git_hash "Tasmanian git hash is not available here") endif() ######################################################################## # Extra directories: # rarely but sometimes find_package() fails to recognize all dependencies # the extra variables here allow the user to circumvent the problem by # including additional directories, also check SparseGrids/CMakeLists.txt # comment about Tasmanian_EXTRA_LIBRARIES and Tasmanian_EXTRA_INCLUDE_DIRS ######################################################################## if (DEFINED Tasmanian_EXTRA_LINK_DIRS) link_directories(${Tasmanian_EXTRA_LINK_DIRS}) # cannot be done per-target endif() ######################################################################## # Report build flags based on the compiler and options ######################################################################## if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(Tasmanian_cxx_flags "${CMAKE_CXX_FLAGS}") else() set(Tasmanian_cxx_flags "${CMAKE_BUILD_TYPE}, ${CMAKE_CXX_FLAGS}") endif() TASMANIAN-8.1/Config/CMakeIncludes/setup_message.cmake000066400000000000000000000051661470551176200224370ustar00rootroot00000000000000######################################################################## # Print the configuration options ######################################################################## message(STATUS "") message(STATUS "Tasmanian ${Tasmanian_VERSION_MAJOR}.${Tasmanian_VERSION_MINOR}${Tasmanian_version_comment}: summary of build options") message(STATUS " -D CMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}") message(STATUS " -D CMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX}") message(STATUS " -D CMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") message(STATUS " -D CMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG}") # useful for Windows debugging message(STATUS " -D CMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}") endif() if (Tasmanian_ENABLE_CUDA) message(STATUS " -D CMAKE_CUDA_FLAGS:STRING=${CMAKE_CUDA_FLAGS}") message(STATUS " -D CMAKE_CUDA_ARCHITECTURES:LIST=${CMAKE_CUDA_ARCHITECTURES}") endif() if (Tasmanian_ENABLE_HIP) message(STATUS " -D CMAKE_HIP_FLAGS:STRING=${CMAKE_HIP_FLAGS}") message(STATUS " -D CMAKE_HIP_ARCHITECTURES:LIST=${CMAKE_HIP_ARCHITECTURES}") endif() message(STATUS " -D BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}") foreach(Tasmanian_option Tasmanian_ENABLE_OPENMP Tasmanian_ENABLE_BLAS Tasmanian_ENABLE_MPI Tasmanian_ENABLE_PYTHON Tasmanian_ENABLE_CUDA Tasmanian_ENABLE_MAGMA Tasmanian_ENABLE_HIP Tasmanian_ENABLE_DPCPP Tasmanian_ENABLE_SWIG Tasmanian_ENABLE_FORTRAN Tasmanian_ENABLE_DOXYGEN) message(STATUS " -D ${Tasmanian_option}:BOOL=${${Tasmanian_option}}") endforeach() if (Tasmanian_MAGMA AND Tasmanian_MAGMA_ROOT) message(STATUS " -D Tasmanian_MAGMA_ROOT:PATH=${Tasmanian_MAGMA_ROOT}") endif() if (NOT "${Tasmanian_MATLAB_WORK_FOLDER}" STREQUAL "") message(STATUS " -D Tasmanian_MATLAB_WORK_FOLDER:PATH=${Tasmanian_MATLAB_WORK_FOLDER}") message(STATUS " pre-install MATLAB folder: addpath('${CMAKE_CURRENT_BINARY_DIR}/MATLAB/matlab/')") endif() message(STATUS "") ######################################################################## # Print final message (a bit of a hack) # The message is written in the CMakeLists.txt, as the subdir is added last # this ensures that the message will appear last in the install process # do not print if USE_XSDK or Tasmanian has been imported with addsubdir ######################################################################## if (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/Config/CMakeIncludes/") endif() TASMANIAN-8.1/Config/CMakeLists.examples.cmake000066400000000000000000000103361470551176200207330ustar00rootroot00000000000000cmake_minimum_required(VERSION @CMAKE_MAJOR_VERSION@.@CMAKE_MINOR_VERSION@) cmake_policy(VERSION @CMAKE_MAJOR_VERSION@.@CMAKE_MINOR_VERSION@) project(Tasmanian_Examples VERSION @Tasmanian_VERSION_MAJOR@.@Tasmanian_VERSION_MINOR@.@Tasmanian_VERSION_PATCH@ LANGUAGES @Tasmanian_langs@) # the following find_package() command will help us locate an existing Tasmanian installation. find_package(Tasmanian @Tasmanian_VERSION_MAJOR@.@Tasmanian_VERSION_MINOR@.@Tasmanian_VERSION_PATCH@ PATHS "@Tasmanian_final_install_path@" REQUIRED @Tasmanian_components@) # The REQUIRED clause above gives a list of all available modules # those correspond to the Tasmanian CMake options. # The SHARED and STATIC modules correspond to the shared and static variants of the libraries. # Each module also comes with a Boolean variable: Tasmanian__FOUND # A project can skip PATHS, and use either: # CMAKE_PREFIX_PATH variable in CMake that includes "@CMAKE_INSTALL_PREFIX@/lib/" # for example using -DCMAKE_PREFIX_PATH="@CMAKE_INSTALL_PREFIX@/lib/" # Tasmanian_DIR or Tasmanian_ROOT environment variables (depending on the version of CMake) # Tasmanian::Tasmanian will be the name of the IMPORTED C++ target. # Tasmanian::Fortran will be the name of the IMPORTED Fortran target. # Additional targets: # Tasmanian::tasgrid will point to the executable ./tasgrid@CMAKE_EXECUTABLE_SUFFIX_CXX@ # Additional variables (if the corresponding options have been enabled): # Tasmanian_PYTHONPATH is the path to the python scripts # Tasmanian_MATLABPATH is the path to the MATLAB scripts # Tasmanian_MATLAB_WORK_FOLDER add_executable(example_sparse_grids example_sparse_grids_01.cpp example_sparse_grids_02.cpp example_sparse_grids_03.cpp example_sparse_grids_04.cpp example_sparse_grids_05.cpp example_sparse_grids_06.cpp example_sparse_grids_07.cpp example_sparse_grids_08.cpp example_sparse_grids_09.cpp example_sparse_grids_10.cpp example_sparse_grids_11.cpp example_sparse_grids.cpp) add_executable(example_dream example_dream_01.cpp example_dream_02.cpp example_dream_03.cpp example_dream_04.cpp example_dream_05.cpp example_dream.cpp) add_executable(example_optimization example_optimization_01.cpp example_optimization_02.cpp example_optimization.cpp) target_link_libraries(example_sparse_grids Tasmanian::Tasmanian) target_link_libraries(example_dream Tasmanian::Tasmanian) target_link_libraries(example_optimization Tasmanian::Tasmanian) # if the Fortran component was found # can also use "if (TARGET Tasmanian::Fortran)" if (Tasmanian_FORTRAN_FOUND) add_executable(example_sparse_grids_fortran example_sparse_grids_01.f90 example_sparse_grids_02.f90 example_sparse_grids_03.f90 example_sparse_grids_04.f90 example_sparse_grids.f90) target_link_libraries(example_sparse_grids_fortran Tasmanian::Fortran) # note that as of 7.1 Tasmanian::Fortran is not equivalent to Tasmanian::Tasmanian if (@Tasmanian_ifort_compiler@) set_target_properties(example_sparse_grids_fortran PROPERTIES LINKER_LANGUAGE Fortran) else() set_target_properties(example_sparse_grids_fortran PROPERTIES LINKER_LANGUAGE CXX) endif() # the LINKER_LANGUAGE property is required by some compilers, e.g., Intel ifort endif() # Tasmanian also includes the executable target Tasmanian::tasgrid add_custom_command(TARGET example_sparse_grids PRE_BUILD COMMAND Tasmanian::tasgrid -v) TASMANIAN-8.1/Config/Tasmanian.h000066400000000000000000000053461470551176200162060ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ /*! * \file Tasmanian.h * \brief Master header to include all modules. * \author Miroslav Stoyanov * \ingroup Tasmanian * * The header needed to access all Tasmanian modules. * If using C++, this is equivalent to Tasmanian.hpp, * otherwise it includes the C interfaces. */ #ifndef __TASMANIAN_H #define __TASMANIAN_H #ifdef __cplusplus #include "Tasmanian.hpp" #else #include "TasmanianSparseGrid.h" #endif #endif TASMANIAN-8.1/Config/Tasmanian.hpp000066400000000000000000000060601470551176200165400ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ /*! * \file Tasmanian.hpp * \brief Master header to include all modules. * \author Miroslav Stoyanov * \ingroup Tasmanian * * The header needed to access all Tasmanian modules. */ #ifndef __TASMANIAN_HPP #define __TASMANIAN_HPP /*! * \defgroup Tasmanian Tasmanian * * The Toolkit for Adaptive Stochastic Modeling and Non-Intrusive ApproximatioN * consists of several modules that sit together under the master header: * \code * #include "Tasmanian.hpp" * \endcode * * Note that "Tasmanian.h" is also acceptable and will include "Tasmanian.hpp" in a C++ context * and the C interface headers in the C context (currently, only sparse grids have a C interface). */ #include "TasmanianAddons.hpp" // includes DREAM and Sparse Grid #endif TASMANIAN-8.1/Config/TasmanianConfig.in.cmake000066400000000000000000000127341470551176200205710ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.19) if (TARGET Tasmanian::Tasmanian) return() # exit if Tasmanian has already been found and defined endif() @PACKAGE_INIT@ # https://cmake.org/cmake/help/v3.5/module/CMakePackageConfigHelpers.html#module:CMakePackageConfigHelpers # seems to indicate that I need to pre-pend PACKAGE_ to the variable names after the @PACKAGE_INIT@ macro # but this doesn't seem to work, not sure if this is a "relocatable package" (low concern) include("@Tasmanian_final_install_path@/lib/@CMAKE_PROJECT_NAME@/@CMAKE_PROJECT_NAME@.cmake") if ("@Tasmanian_ENABLE_MPI@" AND NOT TARGET MPI::MPI_CXX) if (NOT MPI_HOME AND NOT DEFINED ENV{MPI_HOME}) if (NOT MPI_CXX_COMPILER) set(MPI_CXX_COMPILER "@MPI_CXX_COMPILER@") endif() if ("@Tasmanian_ENABLE_FORTRAN@" AND NOT MPI_Fortran_COMPILER) set(MPI_Fortran_COMPILER "@MPI_Fortran_COMPILER@") endif() endif() find_package(MPI REQUIRED) endif() add_executable(Tasmanian::tasgrid IMPORTED) set_property(TARGET Tasmanian::tasgrid PROPERTY IMPORTED_LOCATION "@Tasmanian_final_install_path@/bin/tasgrid${CMAKE_EXECUTABLE_SUFFIX_CXX}") add_library(Tasmanian::Tasmanian INTERFACE IMPORTED GLOBAL) # master target target_link_libraries(Tasmanian::Tasmanian INTERFACE Tasmanian_master) if (@Tasmanian_ENABLE_CUDA@) cmake_policy(SET CMP0074 NEW) if (NOT CUDAToolkit_ROOT) set(CUDAToolkit_ROOT "@CUDAToolkit_LIBRARY_ROOT@") endif() find_package(CUDAToolkit REQUIRED) endif() if (@BUILD_SHARED_LIBS@) set(Tasmanian_SHARED_FOUND "ON") add_library(Tasmanian::shared INTERFACE IMPORTED GLOBAL) # master target target_link_libraries(Tasmanian::shared INTERFACE Tasmanian_master) else() set(Tasmanian_STATIC_FOUND "ON") add_library(Tasmanian::static INTERFACE IMPORTED GLOBAL) # master target target_link_libraries(Tasmanian::static INTERFACE Tasmanian_master) if (@Tasmanian_ENABLE_CUDA@) # Since Tasmanian does not transitively include and since all CUDA calls are wrapped in CXX API, # projects do not require cuda language to link to Tasmanian; however, CMake adds the extraneous dependence. # If Tasmanian was build with CUDA and if the user has not explicitly enabled the CUDA language, # then overwrite the CMake generated extraneous CUDA requirements and link with the CXX compiler only. # This hack is not necessary when building shared libraries. if (NOT CMAKE_CUDA_COMPILER) set_target_properties(Tasmanian_libsparsegrid PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX") set_target_properties(Tasmanian_libsparsegrid PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX") endif() endif() endif() if (@Tasmanian_ENABLE_HIP@) list(APPEND CMAKE_PREFIX_PATH /opt/rocm/hip /opt/rocm) foreach(_tsg_package hip @Tasmanian_rocm_dependencies@) find_package(${_tsg_package} REQUIRED) endforeach() endif() if (@Tasmanian_ENABLE_MAGMA@) add_library(Tasmanian::MAGMA INTERFACE IMPORTED) target_link_libraries(Tasmanian::MAGMA INTERFACE @Tasmanian_magma@) target_include_directories(Tasmanian::MAGMA INTERFACE @Tasmanian_magma_h@) endif() if (TARGET tasmanian) # swig Tasmanian Fortran add_library(Tasmanian_libfortran03 INTERFACE IMPORTED GLOBAL) target_link_libraries(Tasmanian_libfortran03 INTERFACE tasmanian) endif() if (TARGET Tasmanian_libfortran03) add_library(Tasmanian::Fortran INTERFACE IMPORTED GLOBAL) target_link_libraries(Tasmanian::Fortran INTERFACE Tasmanian_libfortran03) if (@Tasmanian_ENABLE_FORTRAN90@) target_link_libraries(Tasmanian::Fortran INTERFACE Tasmanian_libfortran90) endif() if (TARGET Tasmanian_libfortranmpi03) target_link_libraries(Tasmanian::Fortran INTERFACE Tasmanian_libfortranmpi03) endif() set(Tasmanian_FORTRAN_FOUND "ON") endif() # export the python path so other projects can configure python scripts if (@Tasmanian_ENABLE_PYTHON@) set_and_check(Tasmanian_PYTHONPATH "@Tasmanian_final_install_path@/share/Tasmanian/python/") set(Tasmanian_PYTHON_FOUND "ON") endif() # export the MATLAB paths so other projects can write files directly to MATLAB if (NOT "@Tasmanian_MATLAB_WORK_FOLDER@" STREQUAL "") set_and_check(Tasmanian_MATLAB_WORK_FOLDER "@Tasmanian_MATLAB_WORK_FOLDER@") set_and_check(Tasmanian_MATLABPATH "@Tasmanian_final_install_path@/share/Tasmanian/matlab/") set(Tasmanian_MATLAB_FOUND "ON") endif() set(Tasmanian_OPENMP_FOUND "@Tasmanian_ENABLE_OPENMP@") set(Tasmanian_BLAS_FOUND "@Tasmanian_ENABLE_BLAS@") set(Tasmanian_MPI_FOUND "@Tasmanian_ENABLE_MPI@") set(Tasmanian_CUDA_FOUND "@Tasmanian_ENABLE_CUDA@") set(Tasmanian_HIP_FOUND "@Tasmanian_ENABLE_HIP@") set(Tasmanian_DPCPP_FOUND "@Tasmanian_ENABLE_DPCPP@") set(Tasmanian_MAGMA_FOUND "@Tasmanian_ENABLE_MAGMA@") # component GPU uses either GPU backend (CUDA or HIP) if (Tasmanian_CUDA_FOUND OR Tasmanian_HIP_FOUND OR Tasmanian_DPCPP_FOUND) set(Tasmanian_GPU_FOUND "ON") endif() # write component info foreach(_tsg_comp ${Tasmanian_FIND_COMPONENTS}) if (Tasmanian_${_tsg_comp}_FOUND) message(STATUS "Tasmanian component ${_tsg_comp}: found") else() if (Tasmanian_FIND_REQUIRED_${_tsg_comp}) message(WARNING "Tasmanian required component ${_tsg_comp}: missing (error)") else() message(STATUS "Tasmanian optional component ${_tsg_comp}: missing") endif() endif() endforeach() unset(_tsg_comp) check_required_components(Tasmanian) TASMANIAN-8.1/Config/TasmanianConfig.in.hpp000066400000000000000000000063741470551176200203030ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_CONFIG_HPP #define __TASMANIAN_CONFIG_HPP #define TASMANIAN_VERSION_MAJOR @Tasmanian_VERSION_MAJOR@ #define TASMANIAN_VERSION_MINOR @Tasmanian_VERSION_MINOR@ #define TASMANIAN_VERSION_STRING "@Tasmanian_VERSION_MAJOR@.@Tasmanian_VERSION_MINOR@@Tasmanian_version_comment@" #define TASMANIAN_LICENSE "@Tasmanian_license@" #define TASMANIAN_GIT_COMMIT_HASH "@Tasmanian_git_hash@" #define TASMANIAN_CXX_FLAGS "@Tasmanian_cxx_flags@" // cmake options propagated to the source code #cmakedefine Tasmanian_ENABLE_BLAS #cmakedefine Tasmanian_ENABLE_CUDA #cmakedefine Tasmanian_ENABLE_HIP #cmakedefine Tasmanian_ENABLE_DPCPP #cmakedefine Tasmanian_ENABLE_MAGMA #cmakedefine Tasmanian_ENABLE_MPI #if defined(Tasmanian_ENABLE_CUDA) || defined(Tasmanian_ENABLE_HIP) || defined(Tasmanian_ENABLE_DPCPP) #define Tasmanian_ENABLE_GPU // One GPU definition #endif // handle variations in library standards #cmakedefine Tasmanian_BLAS_HAS_ZGELQ #endif TASMANIAN-8.1/Config/TasmanianENVsetup.in.sh000077500000000000000000000007701470551176200204270ustar00rootroot00000000000000#!/usr/bin/env bash # source this file to execute tasgrid after install # also sets the python path export PATH=$PATH:"@Tasmanian_final_install_path@"/bin/ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"@Tasmanian_final_install_path@"/lib/ if [[ "@Tasmanian_ENABLE_PYTHON@" == "ON" ]]; then export PYTHONPATH=$PYTHONPATH:"@Tasmanian_PYTHONPATH@" fi # export old and new style cmake search paths export Tasmanian_DIR="@Tasmanian_final_install_path@" export Tasmanian_ROOT="@Tasmanian_final_install_path@" TASMANIAN-8.1/Config/TasmanianMakefile.in000066400000000000000000000004051470551176200200120ustar00rootroot00000000000000Tasmanian_include = -I@Tasmanian_final_install_path@/include/ Tasmanian_link = -L@Tasmanian_final_install_path@/lib/ Tasmanian_libs = -ltasmaniandream -ltasmaniansparsegrid @Tasmanian_libs@ Tarmanian_fortran_libs = -ltasmanianfortran $(Tasmanian_libs) -lstdc++ TASMANIAN-8.1/Config/magma_cmake.patch000066400000000000000000000407711470551176200173660ustar00rootroot000000000000009a10 > enable_language(Fortran) 34,86d34 < # don't regenerate files during make. < # (I think this means you have to manually re-run CMake if CMakeLists changes. < # It fixes the huge problems with CMake interrupting Visual Studio.) < set(CMAKE_SUPPRESS_REGENERATION on) < < < # ---------------------------------------- < # force an out-of-source build, to not overwrite the existing Makefiles < # (out-of-source is cleaner, too) < string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" MAGMA_COMPILE_INPLACE ) < if (MAGMA_COMPILE_INPLACE) < message( FATAL_ERROR "Compiling MAGMA with CMake requires an out-of-source build. To proceed: < rm -rf CMakeCache.txt CMakeFiles/ # delete files in ${CMAKE_SOURCE_DIR} < mkdir build < cd build < cmake .. < make" ) < endif() < < < # ---------------------------------------- < # prefer shared libraries < option( BUILD_SHARED_LIBS "If on, build shared libraries, otherwise build static libraries" ON ) < < # prefer /usr/local/magma, instead of /usr/local. < if (UNIX AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) < set(CMAKE_INSTALL_PREFIX "/usr/local/magma" CACHE PATH "..." FORCE) < endif() < < # ---------------------------------------- < # use C++11 and C99 < # see http://stackoverflow.com/questions/10851247/how-to-activate-c-11-in-cmake < include(CheckCXXCompilerFlag) < include(CheckCCompilerFlag) < CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) < CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) < if (COMPILER_SUPPORTS_CXX11) < set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") < elseif(COMPILER_SUPPORTS_CXX0X) < set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") < else() < message( WARNING "The compiler ${CMAKE_CXX_COMPILER} doesn't support the -std=c++11 flag. Some code may not compile.") < endif() < < CHECK_C_COMPILER_FLAG("-std=c99" COMPILER_SUPPORTS_C99) < if (COMPILER_SUPPORTS_C99) < set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") < else() < message( WARNING "The compiler ${CMAKE_C_COMPILER} doesn't support the -std=c99 flag. Some code may not compile.") < endif() < < < # ---------------------------------------- 90c38 < FortranCInterface_HEADER( ${CMAKE_SOURCE_DIR}/include/magma_mangling_cmake.h MACRO_NAMESPACE MAGMA_ ) --- > FortranCInterface_HEADER( ${CMAKE_CURRENT_SOURCE_DIR}/include/magma_mangling_cmake.h MACRO_NAMESPACE MAGMA_ ) 93d40 < message( STATUS "Building without Fortran compiler" ) 96d42 < message( STATUS " Using ${FORTRAN_CONVENTION} for Fortran calling convention" ) 105c51 < find_package( OpenMP ) --- > find_package( OpenMP QUIET ) 107,109d52 < message( STATUS "Found OpenMP" ) < message( STATUS " OpenMP_C_FLAGS ${OpenMP_C_FLAGS}" ) < message( STATUS " OpenMP_CXX_FLAGS ${OpenMP_CXX_FLAGS}" ) 121,124d63 < if (CUDAToolkit_FOUND) < message( STATUS "Found CUDA ${CUDA_VERSION}" ) < message( STATUS " CUDA_CUDART_LIBRARY: CUDA::cudart" ) < #message( STATUS " CUDA_CUBLAS_LIBRARIES: CUDA::cublas" ) 130,293c69,84 < set(CUDA_SEPARABLE_COMPILATION ON) < < set(__cuda_architectures) < < include_directories( ${CUDAToolkit_INCLUDE_DIRS} ) < < if (GPU_TARGET MATCHES Fermi) < set( GPU_TARGET "${GPU_TARGET} sm_20" ) < endif() < < if (GPU_TARGET MATCHES Kepler) < set( GPU_TARGET "${GPU_TARGET} sm_30 sm_35 sm_37" ) < endif() < < if (GPU_TARGET MATCHES Maxwell) < set( GPU_TARGET "${GPU_TARGET} sm_50" ) < endif() < < if (GPU_TARGET MATCHES Pascal) < set( GPU_TARGET "${GPU_TARGET} sm_60" ) < endif() < < if (GPU_TARGET MATCHES Volta) < set( GPU_TARGET "${GPU_TARGET} sm_70" ) < endif() < < if (GPU_TARGET MATCHES Turing) < set( GPU_TARGET "${GPU_TARGET} sm_75" ) < endif() < < if (GPU_TARGET MATCHES Ampere) < set( GPU_TARGET "${GPU_TARGET} sm_80" ) < endif() < < if (GPU_TARGET MATCHES sm_20) < if (NOT MIN_ARCH) < set( MIN_ARCH 200 ) < endif() < list(APPEND __cuda_architectures 20) < message( STATUS " compile for CUDA arch 2.0 (Fermi)" ) < endif() < < if (GPU_TARGET MATCHES sm_30) < if (NOT MIN_ARCH) < set( MIN_ARCH 300 ) < endif() < list(APPEND __cuda_architectures 30) < message( STATUS " compile for CUDA arch 3.0 (Kepler)" ) < endif() < < if (GPU_TARGET MATCHES sm_35) < if (NOT MIN_ARCH) < set( MIN_ARCH 300 ) < endif() < list(APPEND __cuda_architectures 35) < message( STATUS " compile for CUDA arch 3.5 (Kepler)" ) < endif() < < if (GPU_TARGET MATCHES sm_37) < if (NOT MIN_ARCH) < set( MIN_ARCH 300 ) < endif() < list(APPEND __cuda_architectures 37) < message( STATUS " compile for CUDA arch 3.7 (Kepler)" ) < endif() < < if (GPU_TARGET MATCHES sm_50) < if (NOT MIN_ARCH) < set( MIN_ARCH 500 ) < endif() < list(APPEND __cuda_architectures 50) < message( STATUS " compile for CUDA arch 5.0 (Maxwell)" ) < endif() < < if (GPU_TARGET MATCHES sm_52) < if (NOT MIN_ARCH) < set( MIN_ARCH 520 ) < endif() < list(APPEND __cuda_architectures 52) < message( STATUS " compile for CUDA arch 5.2 (Maxwell)" ) < endif() < < if (GPU_TARGET MATCHES sm_53) < if (NOT MIN_ARCH) < set( MIN_ARCH 530 ) < endif() < list(APPEND __cuda_architectures 53) < message( STATUS " compile for CUDA arch 5.3 (Maxwell)" ) < endif() < < if (GPU_TARGET MATCHES sm_60) < if (NOT MIN_ARCH) < set( MIN_ARCH 600 ) < endif() < list(APPEND __cuda_architectures 60) < message( STATUS " compile for CUDA arch 6.0 (Pascal)" ) < endif() < < if (GPU_TARGET MATCHES sm_61) < if (NOT MIN_ARCH) < set( MIN_ARCH 610 ) < endif() < list(APPEND __cuda_architectures 61) < message( STATUS " compile for CUDA arch 6.1 (Pascal)" ) < endif() < < if (GPU_TARGET MATCHES sm_62) < if (NOT MIN_ARCH) < set( MIN_ARCH 620 ) < endif() < list(APPEND __cuda_architectures 62) < message( STATUS " compile for CUDA arch 6.2 (Pascal)" ) < endif() < < if (GPU_TARGET MATCHES sm_70) < if (NOT MIN_ARCH) < set( MIN_ARCH 700 ) < endif() < list(APPEND __cuda_architectures 70) < message( STATUS " compile for CUDA arch 7.0 (Volta)" ) < endif() < < if (GPU_TARGET MATCHES sm_71) < if (NOT MIN_ARCH) < set( MIN_ARCH 710 ) < endif() < list(APPEND __cuda_architectures 71) < message( STATUS " compile for CUDA arch 7.1 (Volta)" ) < endif() < < if (GPU_TARGET MATCHES sm_75) < if (NOT MIN_ARCH) < set( MIN_ARCH 750 ) < endif() < list(APPEND __cuda_architectures 75) < message( STATUS " compile for CUDA arch 7.5 (Turing)" ) < endif() < < if (GPU_TARGET MATCHES sm_80) < if (NOT MIN_ARCH) < set( MIN_ARCH 800 ) < endif() < list(APPEND __cuda_architectures 80) < message( STATUS " compile for CUDA arch 8.0 (Ampere)" ) < endif() < < if (NOT MIN_ARCH) < message( FATAL_ERROR "GPU_TARGET must contain one or more of Fermi, Kepler, Maxwell, Pascal, Volta, Turing, Ampere, or valid sm_[0-9][0-9]" ) < endif() < < set(CUDA_ARCHITECTURES "${__cuda_architectures}") < < add_library(magma_nvcc_flags INTERFACE) < target_compile_options(magma_nvcc_flags < INTERFACE < $<$:--compiler-options;-fPIC,${FORTRAN_CONVENTION}> < ) < < set(MAGMA_HAVE_CUDA "1") < set(MAGMA_CUDA_ARCH_MIN "${MIN_ARCH}") < message( STATUS "Define -DMAGMA_HAVE_CUDA -DMAGMA_CUDA_ARCH_MIN=${MIN_ARCH}" ) < else() < message( STATUS "Could not find CUDA" ) < endif() --- > list(GET CMAKE_CUDA_ARCHITECTURES 0 MIN_ARCH) # MIN_ARCH is the first specified arch > foreach(__cuda_arch ${CMAKE_CUDA_ARCHITECTURES}) > if (${__cuda_arch} LESS ${MIN_ARCH}) > set(MIN_ARCH ${__cuda_arch}) > endif() > endforeach() > > add_library(magma_nvcc_flags INTERFACE) > target_compile_options(magma_nvcc_flags > INTERFACE > $<$:--compiler-options;${FORTRAN_CONVENTION}> > ) > > set(MAGMA_HAVE_CUDA "1") > set(MAGMA_CUDA_ARCH_MIN "${MIN_ARCH}") > message( STATUS "Define -DMAGMA_HAVE_CUDA -DMAGMA_CUDA_ARCH_MIN=${MIN_ARCH}" ) 298,348c89,93 < set( GPU_TARGET "gfx900" CACHE STRING "HIP architectures to compile for" ) < list(APPEND CMAKE_PREFIX_PATH /opt/rocm /opt/rocm/hip) < find_package( HIP ) < if (HIP_FOUND) < message( STATUS "Found HIP ${HIP_VERSION}" ) < message( STATUS " HIP_INCLUDE_DIRS: ${HIP_INCLUDE_DIRS}" ) < message( STATUS "GPU_TARGET: ${GPU_TARGET}" ) < < include_directories( ${HIP_INCLUDE_DIRS} ) < < set(HIP_SEPARABLE_COMPILATION ON) < < if (GPU_TARGET MATCHES kaveri) < set( GPU_TARGET ${GPU_TARGET} gfx700 ) < endif() < < if (GPU_TARGET MATCHES hawaii) < set( GPU_TARGET ${GPU_TARGET} gfx701 ) < endif() < < if (GPU_TARGET MATCHES kabini) < set( GPU_TARGET ${GPU_TARGET} gfx703 ) < endif() < < if (GPU_TARGET MATCHES mullins) < set( GPU_TARGET ${GPU_TARGET} gfx703 ) < endif() < < if (GPU_TARGET MATCHES bonaire) < set( GPU_TARGET ${GPU_TARGET} gfx704 ) < endif() < < if (GPU_TARGET MATCHES carrizo) < set( GPU_TARGET ${GPU_TARGET} gfx801 ) < endif() < < if (GPU_TARGET MATCHES iceland) < set( GPU_TARGET ${GPU_TARGET} gfx802 ) < endif() < < if (GPU_TARGET MATCHES tonga) < set( GPU_TARGET ${GPU_TARGET} gfx802 ) < endif() < < if (GPU_TARGET MATCHES fiji) < set( GPU_TARGET ${GPU_TARGET} gfx803 ) < endif() < < if (GPU_TARGET MATCHES polaris10) < set( GPU_TARGET ${GPU_TARGET} gfx803 ) < endif() --- > list (APPEND CMAKE_PREFIX_PATH /opt/rocm/hip /opt/rocm) > if (IS_DIRECTORY Tasmanian_ENABLE_ROCM) > list (APPEND CMAKE_PREFIX_PATH ${Tasmanian_ENABLE_ROCM}) > endif() > enable_language(HIP) 350,352c95,96 < if (GPU_TARGET MATCHES tongapro) < set( GPU_TARGET ${GPU_TARGET} gfx805 ) < endif() --- > find_package( HIP ) > set(MAGMA_HAVE_HIP "1") 354,356c98,99 < if (GPU_TARGET MATCHES stoney) < set( GPU_TARGET ${GPU_TARGET} gfx810 ) < endif() --- > set_property(TARGET hip::device APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL INTERFACE_HIP_DEVICE_COMPILE) > set_property(TARGET hip::device PROPERTY INTERFACE_HIP_DEVICE_COMPILE ON) 358,377c101,105 < set( DEVCCFLAGS "" ) < set(VALID_GFXS "700;701;702;703;704;705;801;802;803;805;810;900;902;904;906;908;909;90c;1010;1011;1012;1030;1031;1032;1033") < foreach( GFX ${VALID_GFXS} ) < if ( GPU_TARGET MATCHES gfx${GFX} ) < set( DEVCCFLAGS ${DEVCCFLAGS} --amdgpu-target=gfx${GFX} ) < endif() < endforeach() < < set( DEVCCFLAGS ${DEVCCFLAGS} -fPIC ${FORTRAN_CONVENTION} ) < set(MAGMA_HAVE_HIP "1") < message( STATUS "Define -DMAGMA_HAVE_HIP" ) < < set_property(TARGET hip::device APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL INTERFACE_HIP_DEVICE_COMPILE) < set_property(TARGET hip::device PROPERTY INTERFACE_HIP_DEVICE_COMPILE ON) < set(GPU_ARCH_FLAGS ${DEVCCFLAGS}) < < #add_compile_options(${GPU_ARCH_FLAGS}) < else() < message( STATUS "Could not find HIP" ) < endif() --- > add_library(magma_hip_flags INTERFACE) > target_compile_options(magma_hip_flags > INTERFACE > $<$:${FORTRAN_CONVENTION}> > ) 400d127 < message( STATUS "Searching for BLAS and LAPACK. To override, set LAPACK_LIBRARIES using ccmake." ) 405d131 < message( STATUS "User set LAPACK_LIBRARIES. To change, edit LAPACK_LIBRARIES using ccmake (set to empty to enable search)." ) 443c169 < include( ${CMAKE_SOURCE_DIR}/CMake.src.cuda ) --- > include( ${CMAKE_CURRENT_SOURCE_DIR}/CMake.src.cuda ) 445c171 < include( ${CMAKE_SOURCE_DIR}/CMake.src.hip ) --- > include( ${CMAKE_CURRENT_SOURCE_DIR}/CMake.src.hip ) 500c226 < include_directories( "${CMAKE_BINARY_DIR}/include" ) --- > include_directories( "${CMAKE_CURRENT_BINARY_DIR}/include" ) 509c235 < --- > 519c245 < configure_file(${CMAKE_SOURCE_DIR}/include/magma_config.h.in ${CMAKE_BINARY_DIR}/include/magma_config.h) --- > configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/magma_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/magma_config.h) 573c299,300 < ) --- > ) > target_include_directories(magma PUBLIC ${CUDAToolkit_INCLUDE_DIRS}) 576,578d302 < if (hipBLAS_FOUND) < message( STATUS "Found rocBLAS ${rocBLAS_VERSION}" ) < endif() 580,582d303 < if (hipSPARSE_FOUND) < message( STATUS "Found rocSPARSE ${rocSPARSE_VERSION}" ) < endif() 589a311 > magma_hip_flags 590a313,319 > target_include_directories(magma PUBLIC ${HIP_INCLUDE_DIRS}) > foreach(__magma_src ${libmagma_all}) > if (NOT ${__magma_src} MATCHES ".F90") > set_source_files_properties(${__magma_src} PROPERTIES LANGUAGE HIP) > endif() > endforeach() > 592c321 < --- > 599c328 < list( APPEND modules "${CMAKE_BINARY_DIR}/${fmod}.mod" ) --- > list( APPEND modules "${CMAKE_CURRENT_BINARY_DIR}/${fmod}.mod" ) 648a378 > include_directories( ${CUDAToolkit_INCLUDE_DIRS} ) 651a382,383 > include_directories( ${HIP_INCLUDE_DIRS} ) > include_directories( ${HIP_INCLUDE_DIRS}/../ ) 668a401 > target_include_directories(magma_sparse PUBLIC ${CUDAToolkit_INCLUDE_DIRS}) 677a411 > magma_hip_flags 678a413,418 > target_include_directories(magma_sparse PUBLIC ${HIP_INCLUDE_DIRS}) > foreach(__magma_src ${libsparse_all}) > if (NOT ${__magma_src} MATCHES ".F90") > set_source_files_properties(${__magma_src} PROPERTIES LANGUAGE HIP) > endif() > endforeach() 681a422,425 > set_property(TARGET magma PROPERTY CXX_STANDARD 11) > set_property(TARGET magma_sparse PROPERTY CXX_STANDARD 11) > set_property(TARGET magma PROPERTY C_STANDARD 99) > set_property(TARGET magma_sparse PROPERTY C_STANDARD 99) 690a435,444 > if (MAGMA_ENABLE_HIP AND IS_DIRECTORY /opt/rocm/llvm/lib) > get_target_property(__magma_rpath magma INSTALL_RPATH) > list(APPEND __magma_rpath /opt/rocm/llvm/lib) > set_target_properties(magma PROPERTIES > BUILD_WITH_INSTALL_RPATH "ON" > INSTALL_RPATH "${__magma_rpath}") > set_target_properties(magma_sparse PROPERTIES > BUILD_WITH_INSTALL_RPATH "ON" > INSTALL_RPATH "${__magma_rpath}") > endif() 720d473 < cmake_policy( SET CMP0037 OLD) 739c492 < file( GLOB headers include/*.h sparse/include/*.h "${CMAKE_BINARY_DIR}/include/*.h" ) --- > file( GLOB headers include/*.h sparse/include/*.h "${CMAKE_CURRENT_BINARY_DIR}/include/*.h" ) 741c494 < file( GLOB headers include/*.h sparse_hip/include/*.h "${CMAKE_BINARY_DIR}/include/*.h" ) --- > file( GLOB headers include/*.h sparse_hip/include/*.h "${CMAKE_CURRENT_BINARY_DIR}/include/*.h" ) 758d510 < message( STATUS "pkgconfig ${pkgconfig}" ) 774c526 < install( FILES "${CMAKE_BINARY_DIR}/${pkgconfig}" --- > install( FILES "${CMAKE_CURRENT_BINARY_DIR}/${pkgconfig}" 779,803d530 < < message( STATUS "Flags" ) < message( STATUS " CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}" ) < message( STATUS " CFLAGS: ${CMAKE_C_FLAGS}" ) < message( STATUS " CXXFLAGS: ${CMAKE_CXX_FLAGS}" ) < if (MAGMA_ENABLE_CUDA) < message( STATUS " NVCCFLAGS: ${CUDA_NVCC_FLAGS}" ) < else() < message( STATUS " DEVCCFLAGS: ${DEVCCFLAGS}" ) < endif() < message( STATUS " FFLAGS: ${CMAKE_Fortran_FLAGS}" ) < message( STATUS " LIBS: ${LIBS}" ) < message( STATUS " blas_fix: ${blas_fix} (MacOS Accelerate only)" ) < message( STATUS " LAPACK_LIBRARIES: ${LAPACK_LIBRARIES}" ) < message( STATUS " INCLUDE_DIRECTORIES: ${MAGMA_INCLUDE}" ) < if (MAGMA_ENABLE_CUDA) < message( STATUS " CUDA_CUDART_LIBRARY: CUDA::cudart" ) < message( STATUS " CUDA_CUBLAS_LIBRARIES: CUDA::cublas" ) < message( STATUS " CUDA_cusparse_LIBRARY: CUDA::cusparse" ) < else() < message( STATUS " HIP_LIBRARY: hip::device" ) < message( STATUS " HIP_BLAS_LIBRARIES: roc::hipblas" ) < message( STATUS " HIP_sparse_LIBRARY: roc::hipsparse" ) < endif() < message( STATUS " Fortran modules: ${modules}" ) TASMANIAN-8.1/DREAM/000077500000000000000000000000001470551176200135355ustar00rootroot00000000000000TASMANIAN-8.1/DREAM/CMakeLists.txt000066400000000000000000000121401470551176200162730ustar00rootroot00000000000000######################################################################## # DREAM librareis and command line tool ######################################################################## add_library(Tasmanian_libdream TasmanianDREAM.hpp tsgDreamState.hpp tsgDreamState.cpp tsgDreamSample.hpp tsgDreamSampleWrapC.cpp tsgDreamLikelihoodCore.hpp tsgDreamLikelyGaussian.hpp tsgDreamLikelyGaussian.cpp tsgDreamCoreRandom.hpp tsgDreamCorePDF.hpp tsgDreamEnumerates.hpp ${CMAKE_CURRENT_SOURCE_DIR}/Optimization/TasmanianOptimization.hpp ${CMAKE_CURRENT_SOURCE_DIR}/Optimization/TasmanianOptimizationWrapC.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Optimization/tsgParticleSwarm.hpp ${CMAKE_CURRENT_SOURCE_DIR}/Optimization/tsgParticleSwarm.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Optimization/tsgGradientDescent.hpp ${CMAKE_CURRENT_SOURCE_DIR}/Optimization/tsgGradientDescent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Optimization/tsgOptimizationUtils.hpp) target_include_directories(Tasmanian_libdream PUBLIC $) target_link_libraries(Tasmanian_libdream Tasmanian_libsparsegrid) set_target_properties(Tasmanian_libdream PROPERTIES OUTPUT_NAME "tasmaniandream" SOVERSION ${Tasmanian_VERSION_MAJOR} VERSION ${PROJECT_VERSION}) Tasmanian_rpath_target(TARGET Tasmanian_libdream COMPONENTS SparseGrids) if (Tasmanian_ENABLE_OPENMP) target_compile_options(Tasmanian_libdream PRIVATE $<$:${OpenMP_CXX_FLAGS}>) endif() install(TARGETS Tasmanian_libdream EXPORT "${Tasmanian_export_name}" RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib") ######################################################################## # add dreamtest and examples executables ######################################################################## add_executable(Tasmanian_dreamtest dreamtest_main.cpp tasdreamExternalTests.hpp tasdreamExternalTests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Optimization/tasdreamOptimizationTests.cpp) set_target_properties(Tasmanian_dreamtest PROPERTIES OUTPUT_NAME "dreamtest" CXX_EXTENSIONS OFF) Tasmanian_rpath_target(TARGET Tasmanian_dreamtest USE_CURRENT COMPONENTS SparseGrids) target_link_libraries(Tasmanian_dreamtest Tasmanian_libdream) ######################################################################## # Testing ######################################################################## add_test(DreamAnalytic dreamtest analytic) add_test(DreamModel dreamtest posterior) add_test(Optimization dreamtest optimization) Tasmanian_set_test_properties(TESTS DreamAnalytic DreamModel) ######################################################################## # Windows specific support (DLL export/import directives and names) ######################################################################## if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") foreach(_tsg_target libdream dreamtest) target_compile_definitions(Tasmanian_${_tsg_target} PRIVATE -D_SCL_SECURE_NO_WARNINGS) endforeach() unset(_tsg_target) if (BUILD_SHARED_LIBS) set_target_properties(Tasmanian_libdream PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) set(Tasmanian_MSVC_PATH_STRING "${CMAKE_CURRENT_BINARY_DIR}/../SparseGrids/Release;${CMAKE_CURRENT_BINARY_DIR}/../SparseGrids/Debug;$ENV{PATH}") string(REPLACE ";" "\\;" Tasmanian_MSVC_PATH_STRING "${Tasmanian_MSVC_PATH_STRING}") set_tests_properties(DreamAnalytic DreamModel Optimization PROPERTIES ENVIRONMENT "PATH=${Tasmanian_MSVC_PATH_STRING}") endif() endif() ######################################################################## # Install headers and config files ######################################################################## install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" DESTINATION include FILES_MATCHING PATTERN "*.hpp" PATTERN "*.windows.*" EXCLUDE PATTERN "*.in.*" EXCLUDE PATTERN "Examples" EXCLUDE) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Optimization/" DESTINATION include FILES_MATCHING PATTERN "*.hpp" PATTERN "*.windows.*" EXCLUDE PATTERN "*.in.*" EXCLUDE PATTERN "Examples" EXCLUDE) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Examples/" DESTINATION "share/Tasmanian/examples/" FILES_MATCHING PATTERN "*.cpp" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) TASMANIAN-8.1/DREAM/Examples/000077500000000000000000000000001470551176200153135ustar00rootroot00000000000000TASMANIAN-8.1/DREAM/Examples/example_dream.cpp000066400000000000000000000030051470551176200206200ustar00rootroot00000000000000#include "Tasmanian.hpp" /*! * \internal * \file example_dream.cpp * \brief Examples for the Tasmanian DREAM module. * \author Miroslav Stoyanov * \ingroup TasmanianDREAMExamples * * The main header required to gain access to the DREAM capabilities of Tasmanian. * The header will include all files needed by the DREAM module including * the TasmanianSparseGrid.hpp header. * \endinternal */ //! \defgroup TasmanianDREAMExamples Examples for the Tasmanian DREAM module //! //! Several examples are included that demonstrate the proper usage of the DREAM interface. //! The examples include random sampling from an arbitrary probability distribution, //! Bayesian inference using a custom model or sparse grids interpolant, //! as well as simple optimization problem (i.e., search for the mode of a probability distribution). using namespace std; #ifndef __TASMANIAN_DOXYGEN_SKIP void dream_example_01(); void dream_example_02(); void dream_example_03(); void dream_example_04(); void dream_example_05(); int main(int argc, const char**){ /* * The purpose of this file is to demonstrate the proper way to call * functions from the TASMANIAN DREAM Module. */ dream_example_01(); dream_example_02(); if (argc > 1) return 0; // fast testing used to check if the library linked correctly dream_example_03(); dream_example_04(); dream_example_05(); cout << "\n" << "---------------------------------------------------------------------------------------------------\n\n"; return 0; } #endif TASMANIAN-8.1/DREAM/Examples/example_dream_01.cpp000066400000000000000000000115421470551176200211250ustar00rootroot00000000000000#include "Tasmanian.hpp" using namespace std; /*! * \internal * \file example_dream_01.cpp * \brief Examples for the Tasmanian DREAM module. * \author Miroslav Stoyanov * \ingroup TasmanianDREAMExamples * * Tasmanian DREAM Example 1 * \endinternal */ /*! * \ingroup TasmanianDREAMExamples * \addtogroup TasmanianDREAMExamples1 Tasmanian DREAM module, example 1 * * Example 1: * Demonstrates how to make a custom probability distribution and use Tasmanian DREAM * to generate random samples. */ //! \brief DREAM Example 1: sample from a custom defined probability distribution. //! \ingroup TasmanianDREAMExamples1 //! \snippet DREAM/Examples/example_dream_01.cpp DREAM_Example_01 example void dream_example_01(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [DREAM_Example_01 example] #endif // using the default random engine, but must reset the random number generator srand((int) time(nullptr)); // Example 1: cout << "\n" << "---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(5); cout << "EXAMPLE 1: make your own probability distribution\n" << " sample from the Gaussian distribution: f(x) = exp(-x^2)\n" << " ignoring scaling constants, using 3000 samples\n" << " See the comments in example_dream_01.cpp\n\n"; int num_dimensions = 1, num_chains = 30; int num_burnup_iterations = 200; int num_collect_iterations = 1000; // 1000 iterations with 30 chains gives 30000 samples TasDREAM::TasmanianDREAM state(num_chains, num_dimensions); // need to initialize the chains, create uniform samples in (-2, 2) std::vector initial_chains = TasDREAM::genUniformSamples({-2.0}, {2.0}, num_chains); state.setState(initial_chains); // Main call to Tasmanian DREAM Sampling algorithm TasDREAM::SampleDREAM(num_burnup_iterations, num_collect_iterations, [&](const std::vector &candidates, std::vector &values)-> void{ // use a lambda to implement the formula std::transform(candidates.begin(), candidates.end(), values.begin(), [&](double x)->double{ return std::exp(-x*x); }); }, [&](const std::vector&)->bool{ return true; }, // unbounded state, TasDREAM::dist_uniform, 0.5, // independent update of magnitude 0.5 TasDREAM::const_percent<90> // use 90% differential update ); // compute the mean and variance of the samples std::vector mean, variance; state.getHistoryMeanVariance(mean, variance); cout << "Using regular form:\n" << " mean:" << setw(13) << std::fixed << mean[0] << " error:" << setw(12) << std::scientific << std::abs(mean[0]) << "\n" << " variance:" << setw(13) << std::fixed << variance[0] << " error:" << setw(12) << std::scientific << std::abs(variance[0] - 0.5) << "\n"; // Repeat the same experiment using the log-form state = TasDREAM::TasmanianDREAM(num_chains, num_dimensions); // reset the state state.setState(initial_chains); // set the initial state // sample again, but use the logarithm form of the formula TasDREAM::SampleDREAM (num_burnup_iterations, num_collect_iterations, [&](const std::vector &candidates, std::vector &values)-> void{ // implement the logarithm of the formula std::transform(candidates.begin(), candidates.end(), values.begin(), [&](double x)->double{ return -x*x; }); }, [&](const std::vector&)->bool{ return true; }, // unbound domain state, TasDREAM::dist_uniform, 0.5, // independent update of magnitude 0.5 TasDREAM::const_percent<90> // use 90% differential update ); // get the mean and variance for the logform samples state.getHistoryMeanVariance(mean, variance); cout << "Using logarithm form:\n" << " mean:" << setw(13) << std::fixed << mean[0] << " error:" << setw(12) << std::scientific << std::abs(mean[0]) << "\n" << " variance:" << setw(13) << std::fixed << variance[0] << " error:" << setw(12) << std::scientific << std::abs(variance[0] - 0.5) << "\n"; cout << "\n" << "---------------------------------------------------------------------------------------------------\n"; #ifndef __TASMANIAN_DOXYGEN_SKIP //! [DREAM_Example_01 example] #endif } TASMANIAN-8.1/DREAM/Examples/example_dream_02.cpp000066400000000000000000000172071470551176200211320ustar00rootroot00000000000000#include "Tasmanian.hpp" using namespace std; /*! * \internal * \file example_dream_02.cpp * \brief Examples for the Tasmanian DREAM module. * \author Miroslav Stoyanov * \ingroup TasmanianDREAMExamples * * Tasmanian DREAM Example 2 * \endinternal */ /*! * \ingroup TasmanianDREAMExamples * \addtogroup TasmanianDREAMExamples2 Tasmanian DREAM module, example 2 * * Example 2: * Demonstrates how to solve a Bayesian inference problem for parameter calibration * using a sparse grid approximation to the Bayesian likelihood function. */ //! \brief DREAM Example 2: perform parameter calibration using likelihood that is approximated with a sparse grid. //! \ingroup TasmanianDREAMExamples2 //! \snippet DREAM/Examples/example_dream_02.cpp DREAM_Example_02 example void dream_example_02(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [DREAM_Example_02 example] #endif // using the default random engine, but must reset the random number generator srand((int) time(nullptr)); // Example 2 cout << "\n" << "---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(5); cout << "EXAMPLE 2: set the inference problem: identify model parameters x_0 and x_1\n" << " from data (noise free example)\n" << " model: f(x) = sin(x_0*M_PI*t + x_1), data: d = sin(M_PI*t + 0.3*M_PI)\n" << " t in [0,1], t is discretized with 32 equidistant nodes\n" << " the likelihood is exp(- 16 * (f(x) - d)^2)\n" << " using a sparse grid to interpolate the likelihood\n" << " NOTE: 16 = 32/2 corresponds to the discretization error in t\n\n"; constexpr double pi = 3.14159265358979323846; int num_dimensions = 2; int num_chains = 100; int num_burnup_iterations = 3000; int num_sample_iterations = 100; // the total number of samples is num_chains * num_iterations = 100 * 100 = 10,000 int num_discrete_nodes = 32; // create a lambda function that represents the model, // normally this would be a call to an external code auto model = [&](double x0, double x1, std::vector &data)-> void{ double dt = 1.0 / ((double) data.size()); double t = 0.5 * dt; for(auto &d : data){ d = std::sin(x0 * pi * t + x1); t += dt; } }; // create a lambda function that represents the likelihood // the Tasmanian LikelihoodGaussIsotropic class can be used here, // but the objective of the example is to use sparse grid interpolant for the likelihood // thus we assume that the likelihood formula is potentially much more complex auto likelihood = [&](double scale, std::vector &model_values, std::vector &data)-> double{ double likelihood_value = 0.0; for(size_t j=0; j data(num_discrete_nodes); model(1.0, 0.3 * pi, data); // "true" values: x0 = 1.0, x1 = 0.3 * pi // construct a sparse grid approximation for the log of the likelihood // the sampling will be done in logform // for details consult the documentation of the sparse grids module // define the domain over which the sparse grid will be constructed std::vector domain_a = {0.5, -0.1}, domain_b = {8.0, 1.7}; auto grid = TasGrid::makeGlobalGrid(num_dimensions, 1, 10, // using 10-th order polynomial TasGrid::type_iptotal, TasGrid::rule_clenshawcurtis); grid.setDomainTransform(domain_a, domain_b); TasGrid::loadNeededPoints( [&](std::vector const &x, std::vector &y, size_t)->void{ std::vector model_at_point(num_discrete_nodes); model(x[0], x[1], model_at_point); y[0] = likelihood((double) num_discrete_nodes, model_at_point, data); }, grid, 1); TasDREAM::TasmanianDREAM state(num_chains, grid); // get the dimensions from the sparse grid std::vector init_chains = TasDREAM::genUniformSamples(domain_a, domain_b, num_chains); state.setState(init_chains); // use chains distributed uniformly over the domain // Call to Tasmanian DREAM Sampling algorithm TasDREAM::SampleDREAM (num_burnup_iterations, num_sample_iterations, TasDREAM::posterior(grid, TasDREAM::uniform_prior), grid.getDomainInside(), state, TasDREAM::dist_uniform, 0.5, // independent update of magnitude 0.5 TasDREAM::const_percent<90> // use 90% differential update ); std::vector expectation, variance; state.getHistoryMeanVariance(expectation, variance); cout << "Inferred values (using 10th order polynomial sparse grid):\n"; cout << " frequency:" << setw(12) << std::fixed << expectation[0] << " error:" << setw(12) << std::scientific << std::abs(expectation[0] - 1.0) << "\n"; cout << " correction:" << setw(12) << std::fixed << expectation[1] << " error:" << setw(12) << std::scientific << std::abs(expectation[1] - 0.3 * pi) << "\n\n"; // Solve the same example, but switch to 30-th order polynomial with a Sequence grid // rebuild the sparse grid interpolant // use 30-th order polynomial and the faster Sequence grid grid.makeSequenceGrid(2, 1, 30, TasGrid::type_iptotal, TasGrid::rule_leja); grid.setDomainTransform(domain_a, domain_b); TasGrid::loadNeededPoints( [&](std::vector const &x, std::vector &y, size_t)-> void{ std::vector model_at_point(num_discrete_nodes); model(x[0], x[1], model_at_point); y[0] = likelihood((double) num_discrete_nodes, model_at_point, data); }, grid, 1); state.clearPDFvalues(); // forget the previous history state.setState(init_chains); // reset the chains // Call to Tasmanian DREAM Sampling algorithm TasDREAM::SampleDREAM (num_burnup_iterations, num_sample_iterations, TasDREAM::posterior(grid, TasDREAM::uniform_prior), grid.getDomainInside(), state, TasDREAM::dist_uniform, 0.5, // independent update of magnitude 0.5 TasDREAM::const_percent<90> // use 90% differential update ); state.getHistoryMeanVariance(expectation, variance); // recompute the statistics cout << "Inferred values (using 30th order polynomial sparse grid):\n"; cout << " frequency:" << setw(12) << std::fixed << expectation[0] << " error:" << setw(12) << std::scientific << std::abs(expectation[0] - 1.0) << "\n"; cout << " correction:" << setw(12) << std::fixed << expectation[1] << " error:" << setw(12) << std::scientific << std::abs(expectation[1] - 0.3 * pi) << "\n\n"; cout << "\n" << "---------------------------------------------------------------------------------------------------\n"; #ifndef __TASMANIAN_DOXYGEN_SKIP //! [DREAM_Example_02 example] #endif } TASMANIAN-8.1/DREAM/Examples/example_dream_03.cpp000066400000000000000000000171011470551176200211240ustar00rootroot00000000000000#include "Tasmanian.hpp" using namespace std; /*! * \internal * \file example_dream_03.cpp * \brief Examples for the Tasmanian DREAM module. * \author Miroslav Stoyanov * \ingroup TasmanianDREAMExamples * * Tasmanian DREAM Example 3 * \endinternal */ /*! * \ingroup TasmanianDREAMExamples * \addtogroup TasmanianDREAMExamples3 Tasmanian DREAM module, example 3 * * Example 3: * Given data that is the superposition of two sin-waves, * use Sparse Grid and Bayesian inference to identify the frequencies and shifts of each wave. * Higher dimensions and bi-modal posterior will decrease the acceptance rate, * thus we need more samples than the previous example. */ //! \brief DREAM Example 3: signal decomposition, using bi-modal posterior distribution. //! \ingroup TasmanianDREAMExamples3 //! \snippet DREAM/Examples/example_dream_03.cpp DREAM_Example_03 example void dream_example_03(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [DREAM_Example_03 example] #endif // using the default random engine, but must reset the random number generator srand((int) time(nullptr)); // EXAMPLE 3: cout << "\n" << "---------------------------------------------------------------------------------------------------\n"; cout << "EXAMPLE 3: set the inference problem: identify x_0 and x_1 model parameters\n" << " from data (noise free example)\n" << " model: f(x) = sin(x_0*M_PI*t + x_1),\n" << " data: d = sin(5*M_PI*t + 0.3*M_PI) + sin(10*M_PI*t + 0.1*M_PI)\n" << " compared to Example 2, the data is a superposition of two signals\n" << " and the posterior is multi-modal\n" << " -- problem setup --\n" << " t in [0,1], t is discretized with 32 equidistant nodes\n" << " the likelihood is exp(- 16 * (f(x) - d)^2)\n" << " using a sparse grid to interpolate the model\n" << " NOTE: 16 = 32/2 corresponds to the discretization error in t\n\n"; constexpr double pi = 3.14159265358979323846; // multi-modal distributions require a lot more chains and samples int num_chains = 500; int num_burnup_iterations = 1000; int num_sample_iterations = 300; // the total number of samples is num_chains * num_iterations int num_discrete_nodes = 32; // create a lambda function that represents the model, // normally this would be a call to an external code auto model = [&](double x0, double x1, std::vector &data)-> void{ double dt = 1.0 / ((double) data.size()); double t = 0.5 * dt; for(auto &d : data){ d = std::sin(x0 * pi * t + x1); t += dt; } }; // create data which is a superposition of two signals std::vector signal1(num_discrete_nodes), signal2(num_discrete_nodes), data(num_discrete_nodes); model( 5.0, 0.3 * pi, signal1); model(10.0, 0.1 * pi, signal2); std::transform(signal1.begin(), signal1.end(), signal2.begin(), data.begin(), std::plus()); auto grid = TasGrid::makeSequenceGrid(2, num_discrete_nodes, 30, // 30-th order polynomial TasGrid::type_iptotal, TasGrid::rule_leja); // set the search interval x_0 in [1, 12], x_1 in [-0.1, 1.7] std::vector domain_a = { 1.0, -0.1}; std::vector domain_b = {12.0, 1.7}; grid.setDomainTransform(domain_a, domain_b); TasGrid::loadNeededPoints( [&](std::vector const &x, std::vector &y, size_t)-> void{ model(x[0], x[1], y); }, grid, 1); // when working with grids with large N, acceleration becomes very useful // if BLAS is enabled on compile time, the grid will use BLAS by default // GPU acceleration can be enabled here using: // grid.enableAcceleration(TasGrid::accel_gpu_cuda); // grid.setGPUID(0); // define the likelihood function and load the data // even though the example is noise free, // we assume that the "noise" is due to discretization error // using piece-wise constant approximation in t, the error is 1.0 / num_discrete_nodes TasDREAM::LikelihoodGaussIsotropic likely(1.0 / ((double) num_discrete_nodes), data); TasDREAM::TasmanianDREAM state(num_chains, grid); // get the dimensions from the sparse grid // use initial chains that are distributed uniformly over the domain state.setState(TasDREAM::genUniformSamples(domain_a, domain_b, num_chains)); // Call to Tasmanian DREAM Sampling algorithm TasDREAM::SampleDREAM (num_burnup_iterations, num_sample_iterations, TasDREAM::posterior (grid, // provide the surrogate model likely, // provide the likelihood TasDREAM::uniform_prior), // assume non-informative prior grid.getDomainInside(), state, TasDREAM::dist_gaussian, 0.01, // independent update of magnitude 0.01 TasDREAM::const_percent<90> // use 90% differential update ); // get the vector containing the sampling history const std::vector &history = state.getHistory(); // splitting the bi-modal history is tricky, use the mid-point of the domain // frequencies below 6.5 will be added to low frequency signal // frequencies above 6.5 will be added to high frequency signal double frequency_low = 0.0, correction_low = 0.0; double frequency_high = 0.0, correction_high = 0.0; int num_low = 0, num_high = 0; for(size_t i=0; i &data)-> void{ double dt = 1.0 / ((double) data.size()); double t = 0.5 * dt; for(auto &d : data){ d = x0 * std::exp(x1 * t) + x2 * std::exp(x3 * t); t += dt; } }; // create data corresponding to 1.0, 1.0, 0.4, 3.0 std::vector data(num_discrete_nodes); model(1.0, 1.0, 0.4, 3.0, data); // add noise to the data, use magnitude (standard deviation) of 1 / num_discrete_nodes // you can adjust the example to consider more/less noise TasDREAM::applyGaussianUpdate(data, 1.0 / ((double) num_discrete_nodes)); auto grid = TasGrid::makeSequenceGrid(4, num_discrete_nodes, 15, // 15-th order polynomial TasGrid::type_iptotal, TasGrid::rule_leja); // set search interval x_0, x_2 in [0.2, 1.2], x_1, x_3 in [0.5, 4.0] std::vector domain_a = {0.2, 0.5, 0.2, 0.5}; std::vector domain_b = {1.2, 4.0, 1.2, 4.0}; grid.setDomainTransform(domain_a, domain_b); TasGrid::loadNeededValues( [&](std::vector const &x, std::vector &y, size_t)-> void{ model(x[0], x[1], x[2], x[3], y); }, grid, 1); // when working with grids with large N, acceleration becomes very useful // if BLAS is enabled on compile time, the grid will use BLAS by default // GPU acceleration can be enabled here using: // grid.enableAcceleration(TasGrid::accel_gpu_cuda); // grid.setGPUID(0); // define the likelihood function and load the data // the discretization error and noise are both is 1.0 / num_discrete_nodes // the Gaussian formula adds another factor of 0.5 which cancels one TasDREAM::LikelihoodGaussIsotropic likely(1.0 / ((double) num_discrete_nodes), data); TasDREAM::TasmanianDREAM state(num_chains, grid); // get the dimensions from the sparse grid std::vector initial_chains; TasDREAM::genUniformSamples(domain_a, domain_b, num_chains, initial_chains); state.setState(initial_chains); // use chains distributed uniformly over the domain // Call to Tasmanian DREAM Sampling algorithm TasDREAM::SampleDREAM (num_burnup_iterations, num_sample_iterations, TasDREAM::posterior (grid, // provide the model likely, // provide the likelihood TasDREAM::uniform_prior), // assume non-informative prior grid.getDomainInside(), state, TasDREAM::dist_gaussian, 0.01, // independent update of magnitude 0.01 TasDREAM::const_percent<100> // use 100% of differential update ); // get the vector containing the sampling history const std::vector &history = state.getHistory(); // splitting the bimodal data is tricky, // add constraint that orders the rates double rate_low = 0.0, scale_low = 0.0; double rate_high = 0.0, scale_high = 0.0; for(size_t i=0; i const &x, std::vector &y)-> void{ double dt = 1.0 / ((double) y.size()); double t = 0.5 * dt; for(auto &output : y){ output = 0.0; int frequency = 1; for(auto const &weight : x) output += weight * std::sin(double(frequency++) * t * pi); t += dt; } }; // the model defined above deals with single set of inputs // sampling requires that models are computed in batch // the size of x will always be a multiple of the number of inputs // the size of y MUST be set to the corresponding multiple of the number of outputs // batch evaluations are best done in parallel auto batch_model = [&](std::vector const &x, std::vector &y)-> void{ int num_samples = (int) x.size() / num_dimensions; y.resize(num_samples * num_discrete_nodes); // use up to 4 threads (if available) int num_threads = std::min((int) std::thread::hardware_concurrency(), 4); std::vector workers(num_threads); for(int start = 0; start void{ for(int i=start; i single_input(&x[i*num_dimensions], &x[i*num_dimensions] + num_dimensions); std::vector single_output(num_discrete_nodes); model(single_input, single_output); std::copy(single_output.begin(), single_output.end(), &y[i*num_discrete_nodes]); } }); } for(auto &w : workers) w.join(); }; std::vector signal = {0.0, 2.0, 0.0, 1.0, 0.0}; std::vector data(num_discrete_nodes); model(signal, data); // add noise to the data, use magnitude 1 / num_discrete_nodes // you can adjust the example to consider more/less noise TasDREAM::applyUniformUpdate(data, 1.0 / ((double) num_discrete_nodes)); // first use Gaussian likelihood: exp( - sigma * (f(x) - d)^2 ) // note that the numerator uses the l-2 norm of the difference between model and data // using smaller variance since we are looking for best-fit (even with the noise) TasDREAM::LikelihoodGaussIsotropic likely(1.0 / ((double) num_discrete_nodes/2), data); // Define the search domain, each parameter is assumed to be in [0, 3] std::vector lower(num_dimensions, 0.0); std::vector upper(num_dimensions, 3.0); TasDREAM::TasmanianDREAM state(num_chains, num_dimensions); auto initial_chains = TasDREAM::genUniformSamples(lower, upper, num_chains); // uniform initial state state.setState(initial_chains); constexpr auto sampling_form = TasDREAM::logform; // ensure uniform sampling form TasDREAM::SampleDREAM (num_burnup_iterations, num_sample_iterations, TasDREAM::posterior (batch_model, // must use the batch model likely, // provide the likelihood TasDREAM::uniform_prior), // assume non-informative prior TasDREAM::hypercube(lower, upper), state, TasDREAM::no_update, TasDREAM::const_percent<100> // use only the differential update ); std::vector solution = state.getApproximateMode(); //cout << " l-2 acceptance rate: " << state.getAcceptanceRate() << endl; cout << "Using Gaussian likelihood, the computed solution is:\n" << " computed: " << std::fixed; for(auto x : solution) cout << setw(13) << x; cout << "\n error: " << std::scientific; for(int i=0; i const &x, std::vector &y)-> void{ int num_samples = (int) x.size() / num_dimensions; // use up to 4 threads (if available) int num_threads = std::min((int) std::thread::hardware_concurrency(), 4); std::vector workers(num_threads); for(int start = 0; start void{ for(int i=start; i single_input(&x[i*num_dimensions], &x[i*num_dimensions] + num_dimensions); std::vector single_output(num_discrete_nodes); model(single_input, single_output); y[i] = 0.0; // compute the l-1 norm of the difference for(int j=0; j (num_burnup_iterations, num_sample_iterations, TasDREAM::posterior (model_likelihood, // provide both the likelihood and the model TasDREAM::uniform_prior), // assume non-informative prior TasDREAM::hypercube(lower, upper), state, TasDREAM::no_update, TasDREAM::const_percent<100> // use only the differential update ); solution = state.getApproximateMode(); //cout << " l-1 acceptance rate: " << state.getAcceptanceRate() << endl; cout << "Using l-1 likelihood, the computed solution is:\n" << " computed: " << std::fixed; for(auto x : solution) cout << setw(13) << x; cout << "\n error: " << std::scientific; for(int i=0; i 1) return 0; // fast testing used to check if the library linked correctly cout << "\n" << "---------------------------------------------------------------------------------------------------\n\n"; return 0; } #endif TASMANIAN-8.1/DREAM/Examples/example_optimization_01.cpp000066400000000000000000000135431470551176200225660ustar00rootroot00000000000000#include "Tasmanian.hpp" using namespace std; /*! * \internal * \file example_optimization_01.cpp * \brief Examples for the Tasmanian Optimization module. * \author Miroslav Stoyanov * \ingroup TasmanianOPTExamples * * Tasmanian Optimization Example 1 * \endinternal */ /*! * \ingroup TasmanianOPTExamples * \addtogroup TasmanianOPTExamples1 Tasmanian Optimization module, example 1 * * Example 1: Particle Swarm method */ /*! * \ingroup TasmanianOPTExamples1 * \brief Optimization Example 1: Demonstrates the use of the Particle Swarm method. * * Find the minimum of the six-hump camel function * \f$ f(x,y) = ( 4 - 2.1 x^2 + x^4 / 3) x^2 + x y + ( - 4 + 4 y^2) y^2 \f$ * the problem is challenging due to the multiple relative and global extrema. * Classic gradient based methods often stagnate and fail when applied to this benchmark problem. * In contrast, the Particle Swarm method uses multiple "particles" that move around the domain * in search for an optimal position. * The "swarm" shares global information and is fairly insensitive to local extrema. * The algorithm shares many similarities with the DREAM sampling procedure * and is a good fit for the Tasmanian framework. * While the method is probabilistic, identifying a correct global minimum * comes with a high probability of success. */ //! \snippet DREAM/Examples/example_optimization_01.cpp OPT_Example_01 example void optimizaiton_example_01(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [OPT_Example_01 example] #endif // using the default random engine, but must reset the random number generator std::srand(std::time(nullptr)); // Example 1: cout << "\n" << "---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(5); cout << "EXAMPLE 1: use the Particle Swarm algorithm to minimize the six-hump camel function\n" << " f(x,y) = (4-2.1 *x^2 + x^4 / 3) * x^2 + x * y + (-4 + 4 * y^2) * y^2\n" << " domain is x in (-3, +3), y in (-2, +2)\n" << " using 50 particles and 200 iterations\n" << " See the comments in example_optimization_01.cpp\n\n"; cout << "the problem has two solutions at (-8.98420e-02, 7.12656e-01) and (8.98420e-02, -7.12656e-01)\n" << "the objective at the solutions is -1.03163.\n\n"; int num_dimensions = 2; int num_particles = 50; TasOptimization::ParticleSwarmState state(num_dimensions, num_particles); state.initializeParticlesInsideBox({-3.0, -2.0}, {3.0, 2.0}); auto objective = TasOptimization::makeObjectiveFunction( num_dimensions, [](const std::vector &x)->double { return (4.0 - 2.1 * x[0]*x[0] + x[0]*x[0]*x[0]*x[0] / 3.0) * x[0]*x[0] + x[0] * x[1] + (-4.0 + 4.0 * x[1]*x[1]) * x[1]*x[1]; }); int num_iterations = 200; double inertia_weight = 0.5, cognitive_coeff = 2.0, social_coeff = 2.0; TasOptimization::ParticleSwarm(objective, TasDREAM::hypercube({-3.0, -2.0}, {3.0, 2.0}), inertia_weight, cognitive_coeff, social_coeff, num_iterations, state); std::vector best_position = state.getBestPosition(); std::vector best_objective(1); objective(best_position, best_objective); cout << "Using the objective function\n" << "found best position after 200 iteration:\n" << "best value for x = " << best_position[0] << "\n" << "best value for y = " << best_position[1] << "\n" << "value of the objective = " << best_objective[0] << "\n\n"; // solve the same optimization problem, but use a sparse grid surrogate // first we create the surrogate, then we optimize auto grid = TasGrid::makeLocalPolynomialGrid(2, 1, 10); grid.setDomainTransform({-3.0, -2.0}, {3.0, 2.0}); std::vector points = grid.getNeededPoints(); std::vector values(grid.getNumNeeded()); objective(points, values); grid.loadNeededValues(values); // at this point, we have the surrogate // reset the state state = TasOptimization::ParticleSwarmState(num_dimensions, num_particles); state.initializeParticlesInsideBox({-3.0, -2.0}, {3.0, 2.0}); // the values of the objective function for all particle positions are computed in batch // thus, the problem is amenable to GPU acceleration // Note: if GPU acceleration is not available, Tasmanian will automatically fallback to CPU grid.enableAcceleration(TasGrid::accel_gpu_cuda); TasOptimization::ParticleSwarm( [&](std::vector const &x, std::vector &y)->void{ grid.evaluateBatch(x, y); }, TasDREAM::hypercube({-3.0, -2.0}, {3.0, 2.0}), inertia_weight, cognitive_coeff, social_coeff, num_iterations, state); best_position = state.getBestPosition(); objective(best_position, best_objective); cout << "Using the surrogate to the objective function\n" << "found best position after 200 iteration:\n" << "best value for x = " << best_position[0] << "\n" << "best value for y = " << best_position[1] << "\n" << "value of the objective = " << best_objective[0] << "\n\n"; cout << "Note: the method will find only one of the minimums\n" << " the random seed will determine which one.\n"; cout << "\n" << "---------------------------------------------------------------------------------------------------\n"; #ifndef __TASMANIAN_DOXYGEN_SKIP //! [OPT_Example_01 example] #endif } TASMANIAN-8.1/DREAM/Examples/example_optimization_02.cpp000066400000000000000000000144041470551176200225640ustar00rootroot00000000000000#include "Tasmanian.hpp" using namespace std; /*! * \internal * \file example_optimization_02.cpp * \brief Examples for the Tasmanian Optimization module. * \author Miroslav Stoyanov * \ingroup TasmanianOPTExamples * * Tasmanian Optimization Example 2 * \endinternal */ /*! * \ingroup TasmanianOPTExamples * \addtogroup TasmanianOPTExamples2 Tasmanian Optimization module, example 2 * * Example 2: Gradient Descent method */ /*! * \ingroup TasmanianOPTExamples2 * \brief Optimization Example 2: Demonstrates the use of the Gradient Descent method * * The Gradient Descent method is both fast converging and very stable, * provided that the objective function has a single relative minimum (e.g., convex), * or the initial starting point is close to the global minimum. * The method is a good complement to the Particle Swarm, where the more slowly * converging particle method can identify the global extrema for a non-convex problem, * and few gradient iterations can quickly zoom into the solution. * * This example uses a very simple quadratic function, the primary goal here is to * demonstrate the syntax rather than compare, contrast or combine different optimization methods. * * \snippet DREAM/Examples/example_optimization_02.cpp OPT_Example_02 example */ void optimizaiton_example_02(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [OPT_Example_02 example] #endif // Example 2: cout << "\n" << "---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(5); cout << "EXAMPLE 2: use Gradient Descent algorithms on a simple quadratic\n" << " f(x,y) = 2.0 * (x - 1.0) * (x - 1.0) + (y - 2.0) * (y - 2.0) / 2.0\n" << " See the comments in example_optimization_02.cpp\n\n"; cout << "Exact solution is at (1.0, 2.0)\n\n"; auto objective = [](std::vector const &x) ->double{ return 2.0 * (x[0] - 1.0) * (x[0] - 1.0) + (x[1] - 2.0) * (x[1] - 2.0) / 2.0; }; // the gradient descent methods require the gradient of the objective auto gradient = [](std::vector const &x, std::vector &grad) ->void{ grad[0] = 4.0 * (x[0] - 1.0); grad[1] = x[1] - 2.0; }; int num_dimensions = 2; double initial_stepsize = 0.0; // the {0.0, 0.0} is a vector with initial state, e.g., initial guess // coupling particle swarm and gradient descent can happen with // auto gradient_state = // TasOptimization::GradientDescentState(particle_state.getBestPosition(), 0.0); TasOptimization::GradientDescentState state({0.0, 0.0}, initial_stepsize); int max_iterations = 200; double tolerance = 1.E-3; TasOptimization::OptimizationStatus status = TasOptimization::GradientDescent(gradient, 1.0/8.0, max_iterations, tolerance, state); std::vector opt_x = state.getX(); cout << "Using the objective function\n" << "aiming at tolerance 1.e-3\n" << "performed iterations: " << status.performed_iterations << "\n" << "best value for x = " << opt_x[0] << "\n" << "best value for y = " << opt_x[1] << "\n\n"; // same problem, but using a surrogate model // construct the surrogate auto grid = TasGrid::makeSequenceGrid(num_dimensions, 1, 2, TasGrid::type_iptotal, TasGrid::rule_leja); std::vector points = grid.getNeededPoints(); std::vector values(grid.getNumNeeded()); for(int i=0; i(points.begin() + 2 * i, points.begin() + 2 * i + 2)); } grid.loadNeededValues(values); // reset the state to zero state = TasOptimization::GradientDescentState({0.0, 0.0}, initial_stepsize); status = TasOptimization::GradientDescent( [&](std::vector const &x, std::vector &grad) ->void{ grid.differentiate(x, grad); }, 1.0/8.0, max_iterations, tolerance, state); opt_x = state.getX(); // actually, since the objective is quadratic, the surrogate is an exact match // the example demonstrates syntax more than anything else cout << "Using the surrogate function\n" << "aiming at tolerance 1.e-3\n" << "performed iterations: " << status.performed_iterations << "\n" << "best value for x = " << opt_x[0] << "\n" << "best value for y = " << opt_x[1] << "\n\n"; // finding optimum inside a box // define the projection operator of a vector into a box // restriction function is probably better name here, since the projection // is not orthogonal // Note: that such restriction is necessary when working with a sparse grid // since the surrogates are usually restricted to a hypercube box. auto projection = [](const std::vector &x, std::vector &p) { p[0] = std::min(std::max(x[0], 0.0), 0.5); p[1] = std::min(std::max(x[1], 0.0), 1.5); }; // reset the state and take the initial_stepsize to 1.0 state = TasOptimization::GradientDescentState({0.0, 0.0}, 1.0); double increase_coeff = 1.25; double decrease_coeff = 1.25; status = TasOptimization::GradientDescent(objective, gradient, projection, increase_coeff, decrease_coeff, max_iterations, tolerance, state); opt_x = state.getX(); // actually, since the objective is quadratic, the surrogate is an exact match // the example demonstrates syntax more than anything else cout << "Using the projection inside of a box\n" << "the solution is at the edge of the box at (0.5, 1.5)\n" << "performed iterations: " << status.performed_iterations << "\n" << "best value for x = " << opt_x[0] << "\n" << "best value for y = " << opt_x[1] << "\n"; cout << "\n" << "---------------------------------------------------------------------------------------------------\n"; #ifndef __TASMANIAN_DOXYGEN_SKIP //! [OPT_Example_02 example] #endif } TASMANIAN-8.1/DREAM/Optimization/000077500000000000000000000000001470551176200162235ustar00rootroot00000000000000TASMANIAN-8.1/DREAM/Optimization/TasmanianOptimization.hpp000066400000000000000000000102131470551176200232530ustar00rootroot00000000000000/* * Copyright (c) 2022, Miroslav Stoyanov & Weiwei Kong * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND * IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF * THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL * ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES * RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING * FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_OPTIMIZATION_HPP #define __TASMANIAN_OPTIMIZATION_HPP #include "tsgParticleSwarm.hpp" #include "tsgGradientDescent.hpp" /*! * \internal * \file TasmanianOptimization.hpp * \brief Optimization states and methods. * \author Weiwei Kong & Miroslav Stoyanov * \ingroup TasmanianOptimization * * The main header required to gain access to the Optimization capabilities of Tasmanian. * The header will include all files needed by the Optimization module including the TasmanianSparseGrid.hpp and * TasmanianDREAM headers. * \endinternal */ /*! * \defgroup TasmanianOptimization Optimization * * \par Optimization * A collection of optimization algorithms for minimizing multivariate real-valued functions. * The algorithms can be applied to both surrogates constructed with sparse grids and * user-provided lambdas. */ /*! * \ingroup TasmanianOptimization * \addtogroup OptimizationState Optimization States * * The Tasmanian framework uses \b states objects to encapsulate meta-data related to the optimization algorithms. * Each algorithm is associated with a separate state class containing specific parameters. */ /*! * \ingroup TasmanianOptimization * \addtogroup OptimizationAlgorithm Optimization Algorithms * * The optimization algorithms are written in functional programming applied to combinations * of objective functionals and optimization states. * The state and the algorithm are split so that different functionals can be used * with a single state in a multi-fidelity paradigm. * An example would be the use of a sparse grid surrogate for the first few steps * of the process and switching to the full-model for the last few iterations. */ /*! * \ingroup TasmanianOptimization * \brief Encapsulates the Tasmanian Optimization module. */ namespace TasOptimization {} #endif TASMANIAN-8.1/DREAM/Optimization/TasmanianOptimizationWrapC.cpp000066400000000000000000000364351470551176200242210ustar00rootroot00000000000000/* * Copyright (c) 2022, Miroslav Stoyanov & Weiwei Kong * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND * IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF * THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL * ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES * RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING * FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_OPTIMIZATION_WRAPC_CPP #define __TASMANIAN_OPTIMIZATION_WRAPC_CPP #include "tsgParticleSwarm.hpp" #include "tsgGradientDescent.hpp" // --------------------------- C Interface for use with Python ctypes and potentially other C codes --------------------------- // // C Function Pointer Aliases using tsg_dream_random = double (*)(); using tsg_optim_dom_fn = int (*)(const int, const double[], int[]); using tsg_optim_obj_fn = void (*)(const int, const int, const double[], double[], int[]); using tsg_optim_obj_fn_single = double (*)(const int, const double[], int[]); using tsg_optim_grad_fn_single = void (*)(const int, const double[], double[], int[]); using tsg_optim_proj_fn_single = void (*)(const int, const double[], double[], int[]); namespace TasOptimization{ // Helper methods to generate some C++ functions from C functions. ObjectiveFunctionSingle convert_C_obj_fn_single(tsg_optim_obj_fn_single func_ptr, std::string err_msg) { return [=](const std::vector &x_single)->double { int err_code = 0; int num_dims = x_single.size(); double result = (*func_ptr)(num_dims, x_single.data(), &err_code); if (err_code != 0) throw std::runtime_error(err_msg); return result; }; } GradientFunctionSingle convert_C_grad_fn_single(tsg_optim_grad_fn_single grad_ptr, std::string err_msg) { return [=](const std::vector &x_single, std::vector &grad)->void { int err_code = 0; int num_dims = x_single.size(); (*grad_ptr)(num_dims, x_single.data(), grad.data(), &err_code); if (err_code != 0) throw std::runtime_error(err_msg); }; } ProjectionFunctionSingle convert_C_proj_fn_single(tsg_optim_proj_fn_single proj_ptr, std::string err_msg) { return [=](const std::vector &x_single, std::vector &proj)->void { int err_code = 0; int num_dims = x_single.size(); (*proj_ptr)(num_dims, x_single.data(), proj.data(), &err_code); if (err_code != 0) throw std::runtime_error(err_msg); }; } extern "C" { // Particle Swarm State. void* tsgParticleSwarmState_Construct(int num_dimensions, int num_particles) { return (void*) new ParticleSwarmState(num_dimensions, num_particles); } void tsgParticleSwarmState_Destruct(void* state) { delete reinterpret_cast(state); } int tsgParticleSwarmState_GetNumDimensions(void* state) { return reinterpret_cast(state)->getNumDimensions(); } int tsgParticleSwarmState_GetNumParticles(void* state) { return reinterpret_cast(state)->getNumParticles(); } void tsgParticleSwarmState_GetParticlePositions(void* state, double pp[]) { reinterpret_cast(state)->getParticlePositions(pp); } void tsgParticleSwarmState_GetParticleVelocities(void* state, double pv[]) { reinterpret_cast(state)->getParticleVelocities(pv); } void tsgParticleSwarmState_GetBestParticlePositions(void* state, double bpp[]) { reinterpret_cast(state)->getBestParticlePositions(bpp); } void tsgParticleSwarmState_GetBestPosition(void* state, double bp[]) { reinterpret_cast(state)->getBestPosition(bp); } int tsgParticleSwarmState_IsPositionInitialized(void* state) { return reinterpret_cast(state)->isPositionInitialized(); } int tsgParticleSwarmState_IsVelocityInitialized(void* state) { return reinterpret_cast(state)->isVelocityInitialized(); } int tsgParticleSwarmState_IsBestPositionInitialized(void* state) { return reinterpret_cast(state)->isBestPositionInitialized(); } int tsgParticleSwarmState_IsCacheInitialized(void* state) { return reinterpret_cast(state)->isCacheInitialized(); } void tsgParticleSwarmState_SetParticlePositions(void* state, const double pp[]) { reinterpret_cast(state)->setParticlePositions(pp); } void tsgParticleSwarmState_SetParticleVelocities(void* state, const double pv[]) { reinterpret_cast(state)->setParticleVelocities(pv); } void tsgParticleSwarmState_SetBestParticlePositions(void* state, const double bpp[]) { reinterpret_cast(state)->setBestParticlePositions(bpp); } void tsgParticleSwarmState_ClearBestParticles(void* state) { reinterpret_cast(state)->clearBestParticles(); } void tsgParticleSwarmState_ClearCache(void* state) { reinterpret_cast(state)->clearCache(); } void tsgParticleSwarmState_InitializeParticlesInsideBox(void* state, const double box_lower[], const double box_upper[], const char* random_type, const int random_seed, tsg_dream_random random_callback) { // Create the U[0,1] random number generator. std::minstd_rand park_miller((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed); std::uniform_real_distribution unif(0.0, 1.0); std::string rtype(random_type); auto randgen = [&]()-> std::function{ if (rtype == "default") { srand((unsigned int) ((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed)); return [&]()->double{ return TasDREAM::tsgCoreUniform01(); }; } else if (rtype == "minstd_rand") { return [&]()->double{ return unif(park_miller); }; } else { return [&]()->double{ return random_callback(); }; } }(); reinterpret_cast(state)->initializeParticlesInsideBox(box_lower, box_upper, randgen); } // Particle Swarm Algorithm. void tsgParticleSwarm(const tsg_optim_obj_fn f_ptr, const tsg_optim_dom_fn inside_ptr, const double inertia_weight, const double cognitive_coeff, const double social_coeff, const int num_iterations, void *state, const char* random_type, const int random_seed, tsg_dream_random random_callback, int *err) { *err = 1; // Create the U[0,1] random number generator. std::minstd_rand park_miller((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed); std::uniform_real_distribution unif(0.0, 1.0); std::string rtype(random_type); auto randgen = [&]()-> std::function{ if (rtype == "default") { srand((unsigned int) ((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed)); return [&]()->double{ return TasDREAM::tsgCoreUniform01(); }; } else if (rtype == "minstd_rand") { return [&]()->double{ return unif(park_miller); }; } else { return [&]()->double{ return random_callback(); }; } }(); auto f_cpp = [=](const std::vector &x_batch, std::vector &fval_batch)->void { int err_code = 0; int num_batch = fval_batch.size(); int num_dims = x_batch.size() / num_batch; (*f_ptr)(num_dims, num_batch, x_batch.data(), fval_batch.data(), &err_code); if (err_code != 0) throw std::runtime_error("The Python objective function callback returned an error in tsgParticleSwarm()"); }; auto inside_cpp = [=](const std::vector &x)->bool { int err_code = 0; int num_dims = x.size(); bool inside = (*inside_ptr)(num_dims, x.data(), &err_code); if (err_code != 0) throw std::runtime_error("The Python domain function callback returned an error in tsgParticleSwarm()"); return inside; }; try { ParticleSwarm(f_cpp, inside_cpp, inertia_weight, cognitive_coeff, social_coeff, num_iterations, *(reinterpret_cast(state)), randgen); *err = 0; // Success } catch (std::runtime_error &) {} } // Gradient Descent State. void* tsgGradientDescentState_Construct(const int num_dimensions, const double x0[], const double initial_stepsize) { return (void*) new GradientDescentState(std::vector(x0, x0 + num_dimensions), initial_stepsize); } void tsgGradientDescentState_Destruct(void* state) { delete reinterpret_cast(state); } int tsgGradientDescentState_GetNumDimensions(void* state) { return reinterpret_cast(state)->getNumDimensions(); } double tsgGradientDescentState_GetAdaptiveStepsize(void* state) { return reinterpret_cast(state)->getAdaptiveStepsize(); } void tsgGradientDescentState_GetX(void* state, double x_out[]) { reinterpret_cast(state)->getX(x_out); } void tsgGradientDescentState_SetAdaptiveStepsize(void* state, const double new_stepsize) { reinterpret_cast(state)->setAdaptiveStepsize(new_stepsize); } void tsgGradientDescentState_SetX(void* state, double x_new[]) { reinterpret_cast(state)->setX(x_new); } // Adaptive Stepsize Projected Gradient Descent Algorithm. OptimizationStatus tsgGradientDescent_AdaptProj(const tsg_optim_obj_fn_single func_ptr, const tsg_optim_grad_fn_single grad_ptr, const tsg_optim_proj_fn_single proj_ptr, const double increase_coeff, const double decrease_coeff, const int max_iterations, const double tolerance, void* state, int* err) { *err = 1; // Convert C functions to safe C++ functions. ObjectiveFunctionSingle func_cpp = convert_C_obj_fn_single(func_ptr, "The Python objective function callback returned an error in tsgGradientDescent()"); GradientFunctionSingle grad_cpp = convert_C_grad_fn_single(grad_ptr, "The Python gradient function callback returned an error in tsgGradientDescent()"); ProjectionFunctionSingle proj_cpp = convert_C_proj_fn_single(proj_ptr, "The Python projection function callback returned an error in tsgGradientDescent()"); // Main call and error handling. OptimizationStatus status; try { status = GradientDescent(func_cpp, grad_cpp, proj_cpp, increase_coeff, decrease_coeff, max_iterations, tolerance, *(reinterpret_cast(state))); *err = 0; // Success } catch (std::runtime_error &) {} return status; } // Adaptive Stepsize (Unconstrained) Gradient Descent Algorithm. OptimizationStatus tsgGradientDescent_Adapt(const tsg_optim_obj_fn_single func_ptr, const tsg_optim_grad_fn_single grad_ptr, const double increase_coeff, const double decrease_coeff, const int max_iterations, const double tolerance, void* state, int* err) { *err = 1; // Convert C functions to safe C++ functions. ObjectiveFunctionSingle func_cpp = convert_C_obj_fn_single(func_ptr, "The Python objective function callback returned an error in tsgGradientDescent()"); GradientFunctionSingle grad_cpp = convert_C_grad_fn_single(grad_ptr, "The Python gradient function callback returned an error in tsgGradientDescent()"); // Main call and error handling. OptimizationStatus status; try { status = GradientDescent(func_cpp, grad_cpp, increase_coeff, decrease_coeff, max_iterations, tolerance, *(reinterpret_cast(state))); *err = 0; // Success } catch (std::runtime_error &) {} return status; } // Constant Stepsize (Unconstrained) Gradient Descent Algorithm. OptimizationStatus tsgGradientDescent_Const(const tsg_optim_grad_fn_single grad_ptr, const double stepsize, const int max_iterations, const double tolerance, void* state, int* err) { *err = 1; // Convert C functions to safe C++ functions. GradientFunctionSingle grad_cpp = convert_C_grad_fn_single(grad_ptr, "The Python gradient function callback returned an error in tsgGradientDescent()"); // Main call and error handling. OptimizationStatus status; try { status = GradientDescent(grad_cpp, stepsize, max_iterations, tolerance, *(reinterpret_cast(state))); *err = 0; // Success } catch (std::runtime_error &) {} return status; } } } #endif TASMANIAN-8.1/DREAM/Optimization/tasdreamOptimizationTests.cpp000066400000000000000000000403521470551176200241650ustar00rootroot00000000000000/* * Copyright (c) 2022, Miroslav Stoyanov & Weiwei Kong * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND * IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF * THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL * ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES * RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING * FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_TASDREAM_OPTIMIZATION_TESTS_CPP #define __TASMANIAN_TASDREAM_OPTIMIZATION_TESTS_CPP #include "TasmanianOptimization.hpp" #include "tasdreamExternalTests.hpp" struct test_result{ void tassert(bool result){ pass_last = result; pass_all = pass_all and pass_last; } bool failed_last() const{ return not pass_last; } bool failed_any() const{ return not pass_all; } bool success() const{ return pass_all; } bool last_success() const{ return pass_last; } private: bool pass_all = true; bool pass_last = true; }; namespace TasOptimization { // Unit tests for TasOptimization::ParticleSwarmState. bool testParticleSwarmState(bool verbose) { test_result test; // Check size of the accessible vectors generated by different constructors. int num_dimensions = 2; int num_particles = 15; std::vector dummy_positions(num_dimensions * num_particles); std::vector dummy_velocities(num_dimensions * num_particles); std::vector states = { ParticleSwarmState(num_dimensions, num_particles), ParticleSwarmState(num_dimensions, std::move(dummy_positions), std::move(dummy_velocities)) }; for (int i=0; i<2; i++) { test.tassert(states[i].getParticlePositions().size() == Utils::size_mult(num_dimensions, num_particles)); test.tassert(states[i].getParticleVelocities().size() == Utils::size_mult(num_dimensions, num_particles)); test.tassert(states[i].getBestParticlePositions().size() == Utils::size_mult(num_dimensions, num_particles+1)); test.tassert(states[i].getBestPosition().size() == (size_t) num_dimensions); std::vector init_vector = states[i].getStateVector(); test.tassert(i == 0 ? not init_vector[0] : init_vector[0]); test.tassert(i == 0 ? not init_vector[1] : init_vector[1]); test.tassert(not init_vector[2]); test.tassert(not init_vector[3]); } // Check TasOptimization::ParticleSwarmState::initializeParticlesInsideBox(). std::vector lower = {-1.0, 1.0}; std::vector upper = {2.0, 3.0}; std::minstd_rand park_miller(42); std::uniform_real_distribution unif(0.0, 1.0); auto get_rand = [&]()->double{ return unif(park_miller); }; states[0].initializeParticlesInsideBox(lower, upper, get_rand); std::vector positions = states[0].getParticlePositions(); std::vector velocities = states[0].getParticleVelocities(); for (int i=0; i= lower[i % num_dimensions] - TasGrid::Maths::num_tol); test.tassert(positions[i] <= upper[i % num_dimensions] + TasGrid::Maths::num_tol); double range = fabs(upper[i % num_dimensions] - lower[i % num_dimensions]); test.tassert(velocities[i] >= -range - TasGrid::Maths::num_tol); test.tassert(velocities[i] <= range + TasGrid::Maths::num_tol); } std::vector init_vector = states[0].getStateVector(); test.tassert(init_vector[0] and init_vector[1]); // Check the nontrivial setters. ParticleSwarmState state(num_dimensions, num_particles); std::vector ones1(num_dimensions * num_particles, 1); std::vector ones2(num_dimensions * (num_particles + 1), 1); state.setParticlePositions(ones1); for (auto p : state.getParticlePositions()) test.tassert(p == 1); state.setParticleVelocities(ones1); for (auto v : state.getParticleVelocities()) test.tassert(v == 1); state.setBestParticlePositions(ones2); for (auto bp : state.getBestParticlePositions()) test.tassert(bp == 1); init_vector = state.getStateVector(); test.tassert(init_vector[0] and init_vector[1] and init_vector[2]); // Check TasOptimization::ParticleSwarmState::clearBestParticles(). state.clearBestParticles(); for (auto bp : states[0].getBestParticlePositions()) test.tassert(bp == 0); init_vector = state.getStateVector(); test.tassert(not init_vector[2]); // Reporting. if (test.failed_any() or verbose) reportPassFail(test.success(), "Particle Swarm", "State Unit Tests"); return test.success(); } // Unit tests for TasOptimization::ParticleSwarm on a single objective function. bool testParticleSwarmSingle(ObjectiveFunction f, ParticleSwarmState state, TasDREAM::DreamDomain inside, int iterations, double optimal_val) { test_result test; // Run the particle swarm algorithm. std::minstd_rand park_miller(42); std::uniform_real_distribution unif(0.0, 1.0); auto get_rand = [&]()->double{ return unif(park_miller); }; ParticleSwarm(f, inside, 0.5, 2, 2, iterations, state, get_rand); // Check optimality and state changes of the run. std::vector best_swarm_point = state.getBestPosition(); std::vector best_swarm_value_vec(1); f(best_swarm_point, best_swarm_value_vec); test.tassert(std::fabs(best_swarm_value_vec[0] - optimal_val) <= TasGrid::Maths::num_tol); std::vector init_vector = state.getStateVector(); test.tassert(init_vector[3]); // Make sure subsequent runs do not make any strange modifications. ParticleSwarm(f, inside, 0.5, 2, 2, 1, state, get_rand); f(best_swarm_point, best_swarm_value_vec); test.tassert(std::fabs(best_swarm_value_vec[0] - optimal_val) <= TasGrid::Maths::num_tol); init_vector = state.getStateVector(); test.tassert(init_vector[3]); // TasOptimization::ParticleSwarmState::clearCache(). state.clearCache(); init_vector = state.getStateVector(); test.tassert(init_vector[0] and init_vector[1] and init_vector[2] and not init_vector[3]); return test.success(); } // Unit tests for TasOptimization::ParticleSwarm on multiple objective functions. bool testParticleSwarm(bool verbose) { test_result test; // l1 norm over the domain [-5, 2] ^ 6. int num_dimensions = 6; int num_particles = 100; int iterations = 300; std::vector lower(num_dimensions, -5.0); std::vector upper(num_dimensions, 2.0); TasOptimization::ObjectiveFunctionSingle l1_single = [](const std::vector &x)->double { double sum = 0; for (auto xi : x) sum += std::fabs(xi); return sum; }; TasOptimization::ObjectiveFunction l1 = TasOptimization::makeObjectiveFunction(num_dimensions, l1_single); TasOptimization::ParticleSwarmState state(num_dimensions, num_particles); state.initializeParticlesInsideBox(lower, upper); test.tassert( testParticleSwarmSingle(l1, state, TasDREAM::hypercube(lower, upper), iterations, 0) ); if (test.failed_last()) std::cout << "ERROR: failed l1 example for Particle Swarm optimization.\n"; // Six hump-camel function over the domain [-3, 3] x [-2, 2]. num_dimensions = 2; num_particles = 50; iterations = 100; lower = {-3.0, -2.0}; upper = {3.0, 2.0}; TasOptimization::ObjectiveFunctionSingle shc_single = [](const std::vector &x)->double { return (4.0 - 2.1 * x[0]*x[0] + x[0]*x[0]*x[0]*x[0] / 3.0) * x[0]*x[0] + x[0] * x[1] + (-4.0 + 4.0 * x[1]*x[1]) * x[1]*x[1];}; TasOptimization::ObjectiveFunction shc = TasOptimization::makeObjectiveFunction(num_dimensions, shc_single); state = ParticleSwarmState(num_dimensions, num_particles); state.initializeParticlesInsideBox(lower, upper); test.tassert( testParticleSwarmSingle(shc, state, TasDREAM::hypercube(lower, upper), iterations, -1.031628453489877) ); if (test.failed_last()) std::cout << "ERROR: failed l1 example for Particle Swarm optimization.\n"; // Reporting. if (test.failed_any() or verbose) reportPassFail(test.success(), "Particle Swarm", "Algorithm Unit Tests"); return test.success(); } // Unit tests for TasOptimization::GradientDescentState. bool testGradientDescentState(bool verbose) { test_result test; // Check contructor. size_t num_dimensions = 5; std::vector dummy_x(num_dimensions, 1); GradientDescentState state = GradientDescentState(dummy_x, 0.1); test.tassert(num_dimensions == state.getNumDimensions()); test.tassert(state.getAdaptiveStepsize() == 0.1); test.tassert(state.getX().size() == num_dimensions); // Check getters and coverters. std::vector compare_x = state.getX(); for (size_t i=0; i new_x(num_dimensions, 2); state.setX(new_x); compare_x = state; for (size_t i=0; i &minimum) { func = [=](const std::vector &x)->double { double result = (L / 4.0) * ((1.0 / 2.0) * (x[0] * x[0] + x[k-1] * x[k-1]) - x[0]); double delta; for (int i=0; i &x, std::vector &gx)->void { std::fill(gx.begin(), gx.end(), 0); gx[0] = (L / 4.0) * (x[0] - 1.0); gx[k-1] = (L / 4.0) * x[k-1]; for (int i=0; i x_optimal(num_dimensions); makeNesterovTestFunction(L, (num_dimensions-1)/2, func, grad, x_optimal); // Constant stepsize gradient descent. std::vector x0(num_dimensions, 0); GradientDescentState state(x0, 0); GradientDescent(grad, 1.0/L, 300, 1E-6, state); std::vector x_gd = state.getX(); for (int i=0; i &x, std::vector &p) { for (size_t i=0; i x0 = state.x; std::vector gx0(num_dimensions), gx(num_dimensions), z0(num_dimensions), xStep(num_dimensions); double fx(func(state.x)), fx0, fxStep; grad(state.x, gx); state.adaptive_stepsize /= increase_coeff; // Offset the first iteration. while(status.residual > tolerance and status.performed_iterations < max_iterations) { // Iteration swaps must be performed first (instead of last) to avoid reverting x to x0 after work has been completed. std::swap(x0, state.x); std::swap(fx0, fx); std::swap(gx0, gx); // Optimistic stepsize update (see γ_d in the referenced paper above). state.adaptive_stepsize *= increase_coeff; // Find the next stepsize/candidate point by making sure it satisfies the well-known descent inequality (see γ_u in the // reference paper associated with this function). double lhs(0), rhs(0); do { if (status.performed_iterations >= max_iterations) return status; lhs = 0; rhs = 0; for (size_t j=0; j rhs + TasGrid::Maths::num_tol); std::swap(xStep, state.x); std::swap(fxStep, fx); state.adaptive_stepsize *= decrease_coeff; // Offset the do-while loop. // Compute residual := ||(x0-x) / stepsize + gx - gx0||_2. grad(state.x, gx); status.residual = computeStationarityResidual(state.x, x0, gx, gx0, state.adaptive_stepsize); } return status; } OptimizationStatus GradientDescent(const ObjectiveFunctionSingle &func, const GradientFunctionSingle &grad, const double increase_coeff, const double decrease_coeff, const int max_iterations, const double tolerance, GradientDescentState &state) { // Wrapper to the proximal version with projection function == identity function. return GradientDescent(func, grad, identity, increase_coeff, decrease_coeff, max_iterations, tolerance, state); } OptimizationStatus GradientDescent(const GradientFunctionSingle &grad, const double stepsize, const int max_iterations, const double tolerance, std::vector &state) { OptimizationStatus status{0, tolerance + 1.0}; // {performed_iterations, residual} size_t num_dimensions = state.size(); std::vector gx(num_dimensions); grad(state, gx); while (status.residual > tolerance and status.performed_iterations < max_iterations) { for (size_t j=0; j Nesterov, Y. (2013). Gradient methods for minimizing composite functions. Mathematical programming, 140(1), 125-161. * */ class GradientDescentState { public: //! \brief The default constructor is NOT allowed. GradientDescentState() = delete; //! \brief Constructor for a gradient descent state with the initial candidate \b x and stepsize \b lambda0. GradientDescentState(const std::vector &x0, const double initial_stepsize) : adaptive_stepsize(initial_stepsize), x(x0) {}; //! \brief Copy constructor. GradientDescentState(const GradientDescentState &source) = default; //! \brief Move constructor. GradientDescentState(GradientDescentState &&source) = default; //! \brief Move assignment. GradientDescentState& operator=(GradientDescentState &&source) = default; //! \brief Copy assignment. GradientDescentState& operator=(GradientDescentState &source) = default; //! \brief Implicit conversion to the current candidate \b x by reference. inline operator std::vector&() {return x;}; //! \brief Return the number of dimensions. inline size_t getNumDimensions() const {return x.size();} //! \brief Return the stepsize. inline double getAdaptiveStepsize() const {return adaptive_stepsize;} //! \brief Return the current candidate point. inline void getX(double x_out[]) const {std::copy_n(x.begin(), x.size(), x_out);} //! \brief Overload for when the output is a vector. inline std::vector getX() const {return x;} //! \brief Set the stepsize. inline void setAdaptiveStepsize(const double new_stepsize) {adaptive_stepsize = new_stepsize;} //! \brief Set the current candidate point. inline void setX(const double x_new[]) {std::copy_n(x_new, x.size(), x.begin());} //! \brief Overload for when the input is a vector. inline void setX(const std::vector &x_new) { checkVarSize("GradientDescentState::setCandidate", "candidate point", x_new.size(), x.size()); x = x_new; } friend OptimizationStatus GradientDescent(const ObjectiveFunctionSingle &func, const GradientFunctionSingle &grad, const ProjectionFunctionSingle &proj, const double increase_coeff, const double decrease_coeff, const int max_iterations, const double tolerance, GradientDescentState &state); friend OptimizationStatus GradientDescent(const ObjectiveFunctionSingle &func, const GradientFunctionSingle &grad, const double increase_coeff, const double decrease_coeff, const int max_iterations, const double tolerance, GradientDescentState &state); friend OptimizationStatus GradientDescent(const GradientFunctionSingle &grad, const double stepsize, const int max_iterations, const double tolerance, std::vector &state); private: double adaptive_stepsize; std::vector x; }; /*! * \brief Applies the constant step-size gradient descent algorithm for functions with unbounded domains. * \ingroup OptimizationAlgorithm * * Minimize a function with gradient \b g over an unconstrained domain. * Perform work until reaching the desired tolerance (measured in the stationarity residual), * or until \b max_iterations is reached. * See also TasOptimization::computeStationarityResidual() * * \param grad Gradient of the objective functional * \param stepsize is the step-size of the algorithm * \param max_iterations is the maximum number of iterations to perform * \param tolerance Stationarity tolerance; the algorithm terminates when the stationarity residual computed by * TasOptimization::computeStationarityResidual() is less than or equal to \b tolerance * \param state contains the current iterate and returns the best iterate. * This algorithm does not use the adaptive step-size, so the state can be just a vector, * but the signature accepts a GradientDescentState with an automatic conversion. * * \returns TasOptimization::OptimizationStatus struct that contains information about the last iterate. */ OptimizationStatus GradientDescent(const GradientFunctionSingle &grad, const double stepsize, const int max_iterations, const double tolerance, std::vector &state); /*! * \brief Applies the adaptive gradient descent algorithm on unrestricted domain. * \ingroup OptimizationAlgorithm Adaptive Non-Proximal Gradient Descent Algorithm * * Similar to the constant step-size algorithm GradientDescent() but applying an adaptive stepping. * This method is guaranteed to converge to a stationary point * if the gradient of \b f is Lipschitz continuous on its domain. * The algorithm is known as Non-Proximal, i.e., no restriction is applied to the domain * which implies either work on an unbounded domain or the starting point and the minimum * are sufficiently far from the boundary and the restriction is not needed. * * This variant requires the value of the functional that is to be minimized, in addition to the gradient. * There are two control parameters \b increase_coeff and \b decrease_coeff that guide the rate * at which the step-size is adjusted. * The parameters can affect the convergence rate, but not the final result. * * \param func is the objective function to be minimized * \param grad is the gradient of the objective function * \param increase_coeff Controls how quickly the step-size is increased; should be greater than 1 * \param decrease_coeff Controls how quickly the step-size is decreased; should be greater than 1 * \param max_iterations Maximum number of iterations to perform * \param tolerance same as in GradientDescent() * \param state Holds the state of the gradient descent algorithm, including the current iterate and the current adaptive step-size. * * \returns TasOptimization::OptimizationStatus struct that contains information about the last iterate. */ OptimizationStatus GradientDescent(const ObjectiveFunctionSingle &func, const GradientFunctionSingle &grad, const double increase_coeff, const double decrease_coeff, const int max_iterations, const double tolerance, GradientDescentState &state); /*! * \brief Applies the adaptive gradient descent algorithm on a restricted domain. * \ingroup OptimizationAlgorithm * * Similar to the adaptive step-size algorithm on the unrestricted domain, * but it uses a projection function to constrain each iterate to a user-defined domain. * * The \b proj function computes the orthogonal projection of a point inside the domain, * e.g., restricts the point to a hypercube. */ OptimizationStatus GradientDescent(const ObjectiveFunctionSingle &func, const GradientFunctionSingle &grad, const ProjectionFunctionSingle &proj, const double increase_coeff, const double decrease_coeff, const int max_iterations, const double tolerance, GradientDescentState &state); } #endif TASMANIAN-8.1/DREAM/Optimization/tsgOptimizationUtils.hpp000066400000000000000000000215701470551176200231660ustar00rootroot00000000000000/* * Copyright (c) 2022, Miroslav Stoyanov & Weiwei Kong * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND * IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF * THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL * ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES * RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING * FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_OPTIM_ENUMERATES_HPP #define __TASMANIAN_OPTIM_ENUMERATES_HPP #include "TasmanianDREAM.hpp" /*! * \internal * \file tsgOptimizationUtils.hpp * \brief Utility functions and aliases in the optimization module. * \author Weiwei Kong & Miroslav Stoyanov * \ingroup TasmanianOptimization * * Defines functions and type aliases that are used in the Tasmanian Optimization module. The file is included in every other * TasOptimization header. * \endinternal */ /*! * \ingroup TasmanianOptimization * \addtogroup OptimizationUtil Miscellaneous utility functions and aliases * * Several type aliases and utility functions similar to the he DREAM module. */ namespace TasOptimization { /*! * \ingroup OptimizationUtil * * Stores information about the run of an optimization algorithm. The \b residual field is algorithm dependent. */ struct OptimizationStatus { //! \brief The number of iterations performed by the current optimization call. int performed_iterations; //! \brief The current residual, e.g., the stationarity residual for the gradient descent. double residual; }; /*! * \internal * \ingroup OptimizationUtil * * Checks if a variable size \b var_name associated with \b var_name inside \b method_name matches an expected size \b exp_size. * If it does not match, a runtime error is thrown. * \endinternal */ inline void checkVarSize(const std::string method_name, const std::string var_name, const int var_size, const int exp_size) { if (var_size != exp_size) { throw std::runtime_error("Size of " + var_name + " (" + std::to_string(var_size) + ") in the function " + method_name + "() is not equal to its expected value of (" + std::to_string(exp_size) + ")"); } } // Functions used in optimization. /*! \ingroup OptimizationUtil * \brief Generic non-batched objective function signature. * * Accepts a single input \b x and returns the value of the function at the point \b x. * * Example of a 2D quadratic function: * \code * ObjectiveFunctionSingle f = [](const std::vector &x)-> * double { * return x[0] * x[0] + 2.0 * x[1] * x[1]; * }; * \endcode */ using ObjectiveFunctionSingle = std::function &x)>; /*! \ingroup OptimizationUtil * \brief Generic batched objective function signature. * * Batched version of TasOptimization::ObjectiveFunctionSingle. * Accepts multiple points \b x_batch and writes their corresponding values into \b fval_batch. * Each point is stored consecutively in \b x_batch so the total size of \b x_batch is * \b num_dimensions times \b num_batch. The size of \b fval_batch is \b num_batch. * The Tasmanian optimization methods will always provide correct sizes for the input, * no error checking is needed. * * Example of a 2D batch quadratic function: * \code * ObjectiveFunction f = [](std::vector const &x, std::vector &y)-> * void { * for(size_t i=0; i &x_batch, std::vector &fval_batch)>; /*! \ingroup OptimizationUtil * \brief Creates a TasOptimization::ObjectiveFunction object from a TasOptimization::ObjectiveFunctionSingle object. * * Given a TasOptimization::ObjectiveFunctionSingle \b f_single and the size of its input \b num_dimensions, * returns a TasOptimization::ObjectiveFunction that evaluates * a batch of points \f$ x_1,\ldots,x_k \f$ to \f$ {\rm f\_single}(x_1),\ldots, {\rm f\_single}(x_k) \f$. */ inline ObjectiveFunction makeObjectiveFunction(const int num_dimensions, const ObjectiveFunctionSingle f_single) { return [=](const std::vector &x_values, std::vector &fval_values)->void { int num_points = x_values.size() / num_dimensions; std::vector x(num_dimensions); for (int i=0; i const &x, std::vector &grad)-> * void { * grad[0] = 2.0 * x[0]; * grad[1] = 4.0 * x[0]; * }; * \endcode */ using GradientFunctionSingle = std::function &x_single, std::vector &grad)>; /*! \ingroup OptimizationUtil * \brief Generic non-batched projection function signature. * * Accepts a single input \b x_single and returns the projection \b proj of \b x_single onto a user-specified domain. * * Example of 2D projection on the box of [-1, 1] * \code * ProjectionFunctionSingle p = [](std::vector const &x, std::vector &p)-> * void { * p[0] = std::min(std::max(x[0], -1.0), 1.0); p[1] = std::min(std::max(x[1], -1.0), 1.0); * }; * \endcode */ using ProjectionFunctionSingle = std::function &x_single, std::vector &proj)>; /*! * \ingroup OptimizationUtil * \brief Generic identity projection function. */ inline void identity(const std::vector &x, std::vector &y) { std::copy(x.begin(), x.end(), y.begin()); } /*! * \ingroup OptimizationUtil * Computes the minimization stationarity residual for a point \b x evaluated from a gradient descent step at \b x0 with stepsize * \b lambda. More specifically, this residual is an upper bound for the quantity: * * \f$ -\inf_{\|d\| = 1, d\in T_C(x)} f'(x;d) \f$ * where \f$ f'(x;d)=\lim_{t \to 0} \frac{ f(x+td)-f(x) }{ t }, \f$ * * the set \f$C\f$ is the domain of \f$f\f$, and \f$T_C(x)\f$ is the tangent cone of \f$C\f$ at \f$x\f$. Here, the gradient of x * (resp. x0) is gx (resp. gx0). */ inline double computeStationarityResidual(const std::vector &x, const std::vector &x0, const std::vector &gx, const std::vector &gx0, const double lambda) { double residual = 0.0; for (size_t i=0; i(num_particles * num_dimensions)), particle_velocities(std::vector(num_particles * num_dimensions)), best_particle_positions(std::vector((num_particles + 1) * num_dimensions)), cache_particle_fvals(std::vector(num_particles, std::numeric_limits::max())), cache_best_particle_fvals(std::vector(num_particles + 1, std::numeric_limits::max())), cache_particle_inside(std::vector(num_particles, false)), cache_best_particle_inside(std::vector(num_particles + 1, false)) {} ParticleSwarmState::ParticleSwarmState(int cnum_dimensions, std::vector &&pp, std::vector &&pv): positions_initialized(true), velocities_initialized(true), best_positions_initialized(false), cache_initialized(false), num_dimensions(cnum_dimensions), num_particles(pp.size() / num_dimensions), particle_positions(std::move(pp)), particle_velocities(std::move(pv)), best_particle_positions(std::vector((num_particles + 1) * num_dimensions)), cache_particle_fvals(std::vector(num_particles, std::numeric_limits::max())), cache_best_particle_fvals(std::vector(num_particles + 1, std::numeric_limits::max())), cache_particle_inside(std::vector(num_particles, false)), cache_best_particle_inside(std::vector(num_particles + 1, false)) {} void ParticleSwarmState::initializeParticlesInsideBox(const double box_lower[], const double box_upper[], const std::function get_random01) { for (int i=0; i &box_lower, const std::vector &box_upper, const std::function get_random01) { checkVarSize("ParticleSwarmState::initializeParticlesInsideBox", "box lower bounds", box_lower.size(), num_dimensions); checkVarSize("ParticleSwarmState::initializeParticlesInsideBox", "box upper bounds", box_upper.size(), num_dimensions); ParticleSwarmState::initializeParticlesInsideBox(box_lower.data(), box_upper.data(), get_random01); } void ParticleSwarm(const ObjectiveFunction f, const TasDREAM::DreamDomain inside, const double inertia_weight, const double cognitive_coeff, const double social_coeff, const int num_iterations, ParticleSwarmState &state, const std::function get_random01) { // Only run the algorithm on properly initialized states. if (!state.positions_initialized) { throw std::runtime_error("Particle positions have not been initialized in the input state object"); } if (!state.velocities_initialized) { throw std::runtime_error("Particle velocities have not been initialized in the input state object"); } // Initialize helper variables and functions. size_t num_dimensions = (size_t) state.getNumDimensions(); size_t num_particles = (size_t) state.getNumParticles(); // Create a lambda that converts f to a constrained version that only evaluates points inside the domain. This lambda also // writes to a bool vector whose i-th entry is true if particle i is in the domain. auto f_constrained = [=](const std::vector &x_batch, std::vector &fval_batch, std::vector &inside_batch)->void { // Collect and apply the domain information given by inside() and x_batch. size_t num_batch(fval_batch.size()), num_inside(0); std::vector candidate(num_dimensions), inside_points; for (size_t i=0; i::max(); std::copy_n(x_batch.begin() + i * num_dimensions, num_dimensions, candidate.begin()); inside_batch[i] = inside(candidate); if (inside_batch[i]) { std::copy_n(candidate.begin(), num_dimensions, std::back_inserter(inside_points)); num_inside++; } } // Evaluate f on the inside points and copy the resulting values to fval_batch. std::vector inside_vals(num_inside); if (num_inside > 0) f(inside_points, inside_vals); int j = 0; for (size_t i=0; ivoid { for (size_t i=0; i rng_cache(2 * num_particles); for(int iter=0; iter(num_particles); i++) { if (state.cache_best_particle_inside[i]) { for(size_t j=0; j(num_particles); i++) { if (state.cache_best_particle_inside[i]) { for(size_t j=0; j M. R. Bonyadi and Z. Michalewicz, "Particle Swarm Optimization for Single Objective Continuous Space Problems: A Review," in * > Evolutionary Computation, vol. 25, no. 1, pp. 1-54, March 2017, doi: 10.1162/EVCO_r_00180. * * \par Clearing the Cache * After an optimization method is applied to the swarm, certain data related to the objective function are stored in cache variables * inside this class. If an optimization method needs to be applied to the swarm with a different objective function than the one used * to generate the cache, the cache \b must be cleared. * - clearCache() * - isCacheInitialized() */ class ParticleSwarmState { public: //! \brief The particle swarm state must be initialized with data that defines number of particles and dimensions. ParticleSwarmState() = delete; //! \brief Constructor for a particle swarm state with the number of particles and dimensions. ParticleSwarmState(const int num_dimensions, const int num_particles); //! \brief Constructor for a particle swarm state with the number of dimensions and the number of particles inferred from //! a set of input particle positions \b pp and a set of input particle velocities \b pv. ParticleSwarmState(const int num_dimensions, std::vector &&pp, std::vector &&pv); //! \brief Copy constructor. ParticleSwarmState(const ParticleSwarmState &source) = default; //! \brief Move constructor. ParticleSwarmState(ParticleSwarmState &&source) = default; //! \brief Move assignment. ParticleSwarmState& operator=(ParticleSwarmState &&source) = default; //! \brief Return the number of dimensions. inline int getNumDimensions() const {return num_dimensions;} //! \brief Return the number of particles. inline int getNumParticles() const {return num_particles;} //! \brief Return the particle positions. inline void getParticlePositions(double pp[]) const {std::copy_n(particle_positions.begin(), num_particles * num_dimensions, pp);} //! \brief Return the particle positions, vector overload. inline std::vector getParticlePositions() const {return particle_positions;} //! \brief Return the particle velocities. inline void getParticleVelocities(double pv[]) const {std::copy_n(particle_velocities.begin(), num_particles * num_dimensions, pv);} //! \brief Return the particle velocities, vector overload. inline std::vector getParticleVelocities() const {return particle_velocities;} /*! * \brief Return the best known particle positions. * * The method actually returns positions with one more than the total number of particles, * the last \b num_dimensions entries of this vector contain the best particle position of the entire swarm. */ inline void getBestParticlePositions(double bpp[]) const {std::copy_n(best_particle_positions.begin(), (num_particles + 1) * num_dimensions, bpp);} //! \brief Return the best known particle positions, vector overload. inline std::vector getBestParticlePositions() const {return best_particle_positions;} //! \brief Loads the best known position in the swarm. inline void getBestPosition(double bp[]) const {std::copy_n(best_particle_positions.begin() + num_particles * num_dimensions, num_dimensions, bp);} //! \brief Returns the best knows position in the swarm. inline std::vector getBestPosition() const { return std::vector(best_particle_positions.begin() + num_particles * num_dimensions, best_particle_positions.begin() + num_particles * num_dimensions + num_dimensions); } //! \brief Returns true if the particle positions have been initialized. inline bool isPositionInitialized() const {return positions_initialized;} //! \brief Returns true if the particle velocities have been initialized. inline bool isVelocityInitialized() const {return velocities_initialized;} //! \brief Returns true if the best particle positions have been initialized. inline bool isBestPositionInitialized() const {return best_positions_initialized;} //! \brief Returns true if the cache has been initialized. inline bool isCacheInitialized() const {return cache_initialized;} //! \brief Return the complete state vector. inline std::vector getStateVector() const { return {positions_initialized, velocities_initialized, best_positions_initialized, cache_initialized}; } //! \brief Set the particle positions, raw-array variant. void setParticlePositions(const double pp[]) { std::copy_n(pp, num_dimensions * num_particles, particle_positions.begin()); positions_initialized = true; } //! \brief Set the particle positions, vector variant. void setParticlePositions(const std::vector &pp) { checkVarSize("ParticleSwarmState::setParticlePositions", "particle position", pp.size(), num_dimensions * num_particles); particle_positions = pp; positions_initialized = true; } //! \brief Set the particle positions, with a move. void setParticlePositions(std::vector &&pp) { checkVarSize("ParticleSwarmState::setParticlePositions", "particle positions", pp.size(), num_dimensions * num_particles); particle_positions = std::move(pp); positions_initialized = true; } //! \brief Set the particle velocities. void setParticleVelocities(const double pv[]) { std::copy_n(pv, num_dimensions * num_particles, particle_velocities.begin()); velocities_initialized = true; } //! \brief Sets the best position. void setParticleVelocities(const std::vector &pv) { checkVarSize("ParticleSwarmState::setParticleVelocities", "particle velocities", pv.size(), num_dimensions * num_particles); particle_velocities = pv; velocities_initialized = true; } //! \brief Sets the best position, with a move. void setParticleVelocities(std::vector &&pv) { checkVarSize("ParticleSwarmState::setParticleVelocities", "particle velocities", pv.size(), num_dimensions * num_particles); particle_velocities = std::move(pv); velocities_initialized = true; } //! \brief Set the previously best known particle velocities. void setBestParticlePositions(const double bpp[]) { std::copy_n(bpp, num_dimensions * (num_particles + 1), best_particle_positions.begin()); best_positions_initialized = true; } //! \brief Sets the best position per particle. void setBestParticlePositions(const std::vector &bpp) { checkVarSize("ParticleSwarmState::setBestParticlePositions", "best particle positions", bpp.size(), num_dimensions * (num_particles + 1)); best_particle_positions = bpp; best_positions_initialized = true; } //! \brief Sets the best position per particle, allows for a move. void setBestParticlePositions(std::vector &&bpp) { checkVarSize("ParticleSwarmState::setBestParticlePositions", "best particle positions", bpp.size(), num_dimensions * (num_particles + 1)); best_particle_positions = std::move(bpp); best_positions_initialized = true; } //! \brief Clear the previously best known particle velocities. void clearBestParticles() { best_positions_initialized = false; std::fill(best_particle_positions.begin(), best_particle_positions.end(), 0.0); } //! \brief Clear the particle swarm cache. void clearCache() { cache_initialized = false; std::fill(cache_particle_fvals.begin(), cache_particle_fvals.end(), 0.0); std::fill(cache_particle_inside.begin(), cache_particle_inside.end(), false); std::fill(cache_best_particle_fvals.begin(), cache_best_particle_fvals.end(), 0.0); std::fill(cache_best_particle_inside.begin(), cache_best_particle_inside.end(), false); } /*! \brief Randomly initializes all of the particle positions and velocities inside of a box. * * The i-th component of each particle's position is uniformly sampled from the interval [\b box_lower[i], \b box_upper[i]]. * The i-th velocity of each particle's velocity is uniformly sampled from the interval [-R, R] where R = * abs(\b box_upper[i] - \b box_lower[i]). The uniform [0,1] random number generator used in the sampling is specified * by \b get_random01. */ void initializeParticlesInsideBox(const double box_lower[], const double box_upper[], const std::function get_random01 = TasDREAM::tsgCoreUniform01); //! \brief Randomly initializes all of the particles, vector API overload. void initializeParticlesInsideBox(const std::vector &box_lower, const std::vector &box_upper, const std::function get_random01 = TasDREAM::tsgCoreUniform01); friend void ParticleSwarm(const ObjectiveFunction f, const TasDREAM::DreamDomain inside, const double inertia_weight, const double cognitive_coeff, const double social_coeff, const int num_iterations, ParticleSwarmState &state, const std::function get_random01); private: bool positions_initialized, velocities_initialized, best_positions_initialized, cache_initialized; int num_dimensions, num_particles; std::vector particle_positions, particle_velocities, best_particle_positions, cache_particle_fvals, cache_best_particle_fvals; std::vector cache_particle_inside, cache_best_particle_inside; }; // Forward declarations. /*! * \brief Applies the classic particle swarm algorithm to a particle swarm state. * \ingroup OptimizationAlgorithm * * Runs \b num_iterations of the particle swarm algorithm to a particle swarm \b state to minimize the function \b f over the * domain \b inside. The parameters of the algorithm are \b inertia_weight , \b cognitive_coeff , and \b social_coeff. The * uniform [0,1] random number generator used by the algorithm is \b get_random01. * * \param f Objective function to be minimized * \param inside indicates whether a given point is inside or outside of the domain of interest * \param inertia_weight inertial weight for the particle swarm algorithm * \param cognitive_coeff cognitive coefficient for the particle swarm algorithm * \param social_coeff social coefficient for the particle swarm algorithm * \param num_iterations number of iterations to perform * \param state holds the state of the particles, e.g., positions and velocities, see TasOptimization::ParticleSwarmState * \param get_random01 random number generator, defaults to rand() * * \throws std::runtime_error if either the positions or the velocities of the \b state have not been initialized */ void ParticleSwarm(const ObjectiveFunction f, const TasDREAM::DreamDomain inside, const double inertia_weight, const double cognitive_coeff, const double social_coeff, const int num_iterations, ParticleSwarmState &state, const std::function get_random01 = TasDREAM::tsgCoreUniform01); } #endif TASMANIAN-8.1/DREAM/TasmanianDREAM.hpp000066400000000000000000000102601470551176200167310ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_HPP #define __TASMANIAN_DREAM_HPP #include "tsgDreamSample.hpp" #include "tsgDreamLikelyGaussian.hpp" /*! * \internal * \file TasmanianDREAM.hpp * \brief DiffeRential Evolution Adaptive Metropolis methods. * \author Miroslav Stoyanov * \ingroup TasmanianDREAM * * The main header required to gain access to the DREAM capabilities of Tasmanian. * The header will include all files needed by the DREAM module including * the TasmanianSparseGrid.hpp header. * \endinternal */ /*! * \defgroup TasmanianDREAM DREAM: DiffeRential Evolution Adaptive Metropolis * * \par DREAM * The DiffeRential Evolution Adaptive Metropolis is a method to draw samples * from an arbitrary probability distribution defined by an arbitrary non-negative function * (not necessarily normalized to integrate to 1). * In the Tasmanian DREAM module, the samples (and the history) are stored in * a TasDREAM::TasmanianDREAM state object which also defines the number of samples * and the number of dimensions of the input space. * The sampling is performed by the TasDREAM::SampleDREAM() template * that takes an initialized state and several callable objects that describe * the geometry of the domain and the parameters of the sampling, e.g., number of iterations. * * \par Bayesian Inference * One of the most common applications for DREAM is in the context of Bayesian inference, * where the probability distribution is comprised of a model, likelihood and prior. * The three components can be combined together with the TasDREAM::posterior() * template, which returns a callable object that represents the probability distribution. * * \par Examples * See the included examples. */ /*! * \ingroup TasmanianDREAM * \brief Encapsulates the Tasmanian DREAM module. * * DREAM related classes and methods sit under the TasDREAM namespace. */ namespace TasDREAM{} #endif TASMANIAN-8.1/DREAM/dreamtest_main.cpp000066400000000000000000000107071470551176200172420ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "gridtestCLICommon.hpp" #include "tasdreamExternalTests.hpp" using namespace std; void printHelp(); int main(int argc, const char ** argv){ //cout << " Phruuuuphrrr " << endl; // this is the sound that the Tasmanian devil makes std::deque args = stringArgs(argc, argv); if (!args.empty() && hasHelp(args.front())){ printHelp(); return 0; } bool debug = false; TypeDREAMTest test = test_all; DreamExternalTester tester; while(!args.empty()){ if (hasInfo(args.front())){ tester.showVerbose(); if ((args.front() == "verbose") || (args.front() == "-verbose")) tester.showStatsValues(); }else if (hasRandom(args.front())) tester.useRandomRandomSeed(); else if (args.front() == "debug") debug = true; else if (args.front() == "analytic") test = test_analytic; else if (args.front() == "posterior") test = test_posterior; else if (args.front() == "optimization") test = test_optimization; else if (args.front() == "all") test = test_all; else{ cerr << "ERROR: Unknown option '" << args.front() << "'" << endl; cerr << " to see list of available options use: ./dreamtest --help" << endl; return 1; } args.pop_front(); } if (debug){ testDebug(); return 0; } return (tester.performTests(test)) ? 0 : 1; } void printHelp(){ cout << endl; cout << "Usage: dreamtest ...\n\n"; cout << "Commands\tAction\n"; cout << "all\t\tRun all tests (default if no commands are given)\n"; cout << "analytic\tRun the tests associated with analytic probability distributions\n"; cout << "posterior\tRun the tests associated with Bayesian inference\n"; cout << "-v\t\tShow verbose test information\n"; cout << "verbose\t\tIn addition to -v also shows critical test values\n"; cout << "random\t\tDo not use the hard-coded random seed, use the time as random seed\n"; cout << "debug\t\tRun the code implemented in tasdreamExternalTests.cpp function testDebug()\n"; cout << endl; } TASMANIAN-8.1/DREAM/tasdreamExternalTests.cpp000066400000000000000000000640401470551176200205730ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_TASDREAM_EXTERNAL_TESTS_CPP #define __TASMANIAN_TASDREAM_EXTERNAL_TESTS_CPP #include "tasdreamExternalTests.hpp" double DreamExternalTester::getChiValue(size_t num_degrees){ switch(num_degrees){ case 9: return 21.666; case 15: return 30.578; case 19: return 36.191; case 20: return 37.566; case 24: return 42.980; case 49: return 74.919; case 99: return 134.642; case 124: return 163.546; default: throw std::runtime_error("ERROR: Unknown degrees of freedom for the Chi-squared test."); } } bool DreamExternalTester::testFit(const std::vector &cell_count_a, const std::vector &cell_count_b){ double suma = (double) std::accumulate(cell_count_a.begin(), cell_count_a.end(), 0); double sumb = (double) std::accumulate(cell_count_b.begin(), cell_count_b.end(), 0); double scale = std::sqrt(sumb / suma); double test_value = 0.0; auto ia = cell_count_a.begin(), ib = cell_count_b.begin(); while(ia != cell_count_a.end()){ double diff = ((double) *ia) * scale - ((double) *ib) / scale; double sum = (double) (*ia++ + *ib++); if (sum > 0.0) test_value += diff * diff / sum; } bool pass = (test_value < getChiValue(cell_count_a.size() - 1)); if (!pass || showvalues){ if (!pass) cout << "Chi-Squared test FAILED" << endl; cout << "Totals: " << suma << " " << sumb << endl; cout << "Chi-Squared test value = " << test_value << " num cells: " << cell_count_a.size() << endl; cout << "Critical Chi-Squared value = " << getChiValue(cell_count_a.size() - 1) << endl; } return pass; } void DreamExternalTester::binHypercubeSamples(const std::vector &lower, const std::vector &upper, int num_bins1D, const std::vector &data, std::vector &bin_count){ size_t num_dimensions = lower.size(); if (upper.size() != num_dimensions) throw std::runtime_error("ERROR: upper and lower must have the same size in binHypercubeSamples() DREAM testing"); std::vector dx(num_dimensions); auto il = lower.begin(), iu = upper.begin(); for(auto &d : dx) d = (*iu++ - *il++) / ((double) num_bins1D); size_t num_bins = 1; for(size_t i=0; i(num_bins, 0); auto id = data.begin(); while(id != data.end()){ std::vector binid(num_dimensions); il = lower.begin(); iu = dx.begin(); for(auto &i : binid){ i = (size_t) ((*id++ - *il++) / *iu++); if (i >= (size_t) num_bins1D) i = num_bins1D-1; } size_t bin_index = 0; for(auto i : binid) bin_index = num_dimensions * bin_index + i; bin_count[bin_index]++; } } bool DreamExternalTester::compareSamples(const std::vector &lower, const std::vector &upper, int num_bins1D, const std::vector &data1, const std::vector &data2){ std::vector count1, count2; binHypercubeSamples(lower, upper, num_bins1D, data1, count1); binHypercubeSamples(lower, upper, num_bins1D, data2, count2); return testFit(count1, count2); } bool DreamExternalTester::testGaussian3D(){ bool passAll = true; int num_dimensions = 3; int num_samples = 1000, num_chains = 20; int num_iterations = num_samples / num_chains + 2; int num_burnup = 20 * num_iterations; std::minstd_rand park_miller(42); if (usetimeseed) park_miller.seed(getRandomRandomSeed()); std::uniform_real_distribution unif(0.0, 1.0); auto get_rand = [&]()->double{ return unif(park_miller); }; // compute reference samples, mean 2.0, std 3.0 std::vector means(num_dimensions, 2.0), deviations(num_dimensions, 3.0); std::vector tresult = genGaussianSamples(means, deviations, num_samples, get_rand); // Use DREAM with zero-weight (i.e., standard Metropolis-Hastings) TasmanianDREAM state(num_chains, num_dimensions); // initialize with correct mean 2.0, std 3.0 std::vector initial_state = genGaussianSamples(means, deviations, num_chains, get_rand); state.setState(initial_state); SampleDREAM(num_burnup, num_iterations, [&](const std::vector &candidates, std::vector &values){ // 3D Gaussian PDF with standard deviation of 3.0 auto ix = candidates.begin(); for(auto &v : values) v = getDensity(*ix++, 2.0, 9.0) * getDensity(*ix++, 2.0, 9.0) * getDensity(*ix++, 2.0, 9.0); }, [&](const std::vector&)->bool{ return true; }, // unbounded domain state, [&](std::vector &x){ applyGaussianUpdate(x, 3.0, [&]()->double{ return unif(park_miller); }); }, const_percent<0>, // independent chains, no differential proposal get_rand ); std::vector upper(num_dimensions, 11.0), lower(num_dimensions, -7.0); // compute over a box of 3 standard deviations bool pass = compareSamples(lower, upper, 5, tresult, state.getHistory()); passAll = passAll && pass; if (verbose || !pass) reportPassFail(pass, "Gaussian 3D", "with independent chains"); state = TasmanianDREAM(num_chains, num_dimensions); // reinitialize state.setState(initial_state); SampleDREAM(num_burnup, 2*num_iterations, [&](const std::vector &candidates, std::vector &values){ // 3D Gaussian PDF with standard deviation of 3.0 auto ix = candidates.begin(); for(auto &v : values) v = getDensity(*ix++, 2.0, 9.0) * getDensity(*ix++, 2.0, 9.0) * getDensity(*ix++, 2.0, 9.0); }, hypercube(lower, upper), // large domain state, dist_uniform, 0.2, // uniform proposal const_percent<50>, // differential proposal is weighted by 50% get_rand ); pass = compareSamples(lower, upper, 5, tresult, state.getHistory()) && (state.getAcceptanceRate() > 0.5); passAll = passAll && pass; if (verbose || !pass) reportPassFail(pass, "Gaussian 3D", "with correlated chains"); // test anisotropic Gaussian likelihood // compute reference samples, compute initial set from the true solution, reinitialize the state tresult = genGaussianSamples({1.5, 2.0, 2.5}, {0.5, 1.0, 2.0}, num_samples, get_rand); initial_state = genGaussianSamples({1.5, 2.0, 2.5}, {0.5, 1.0, 2.0}, num_chains, get_rand); state = TasmanianDREAM(num_chains, num_dimensions); // reinitialize state.setState(initial_state); LikelihoodGaussAnisotropic likely({0.25, 1.0, 4.0}, {1.5, 2.0, 2.5}, 1); if (likely.getNumOutputs() != 3) throw std::runtime_error("LikelihoodGaussAnisotropic has wrong num outputs"); SampleDREAM(num_burnup, num_iterations, posterior( [&](const std::vector &candidates, std::vector &values){ values = candidates; // the model is identity }, likely, uniform_prior), hypercube(lower, upper), // large domain state, dist_uniform, 0.2, const_percent<50>, // differential proposal is weighted by 50% get_rand ); pass = compareSamples(lower, upper, 5, tresult, state.getHistory()) && (state.getAcceptanceRate() > 0.5); std::vector mean, variance; state.getHistoryMeanVariance(mean, variance); std::vector tmean = {1.5, 2.0, 2.5}, tvar = {0.25, 1.0, 4.0}; for(int i=0; i<3; i++) { if (std::abs(mean[i] - tmean[i]) / tmean[i] > 0.3){ cout << "error in mean exceeded: " << std::abs(mean[i] - tmean[i]) / tmean[i] << endl; pass = false; } if (std::abs(variance[i] - tvar[i]) / tvar[i] > 0.6){ cout << "error in variance exceeded: " << std::abs(variance[i] - tvar[i]) / tvar[i] << endl; pass = false; } } state = TasmanianDREAM(); // reset to empty test if (state.getNumDimensions() != 0) throw std::runtime_error("TasmanianDREAM has wrong num dimensions"); passAll = passAll && pass; if (verbose || !pass) reportPassFail(pass, "Gaussian 3D", "with anisotropic likelihood"); reportPassFail(passAll, "Gaussian 3D", "DREAM vs Box-Muller"); return passAll; } bool DreamExternalTester::testGaussian2D(){ bool passAll = true; int num_dimensions = 2; int num_samples = 1000, num_chains = 20; int num_iterations = num_samples / num_chains + 2; int num_burnup = 20 * num_iterations; std::minstd_rand park_miller(42); if (usetimeseed) park_miller.seed(getRandomRandomSeed()); std::uniform_real_distribution unif(0.0, 1.0); auto get_rand = [&]()->double{ return unif(park_miller); }; // compute reference samples, mean 0.3, std 0.15 (3 deviations fit in [-1, 1]^2) std::vector tresult(num_dimensions * num_samples, 0.3); applyGaussianUpdate(tresult, 0.15, get_rand); // approximate the pdf in log-form, log-form of the Gaussian pdf is quadratic, the grid gives exact match TasGrid::TasmanianSparseGrid grid; grid.makeSequenceGrid(2, 1, 2, TasGrid::type_iptotal, TasGrid::rule_rleja); // interpolates exactly all quadratic polynomials std::vector grid_points, values; grid.getNeededPoints(grid_points); values.resize(grid_points.size() / 2); auto ip = grid_points.begin(); for(auto &v : values) v = getDensity(*ip++, 0.3, 0.0225) + getDensity(*ip++, 0.3, 0.0225); grid.loadNeededPoints(values); // initialize the DREAM state TasmanianDREAM state(num_chains, num_dimensions); std::vector initial_set(num_chains * num_dimensions, 0.0); // initialize with uniform samples applyUniformUpdate(initial_set, 1.0, get_rand); state.setState(initial_set); SampleDREAM(num_burnup, num_iterations, posterior(grid, uniform_prior), grid.getDomainInside(), state, dist_gaussian, 0.1, const_percent<98>, // correlated chains get_rand ); std::vector upper(num_dimensions, 1.0), lower(num_dimensions, -1.0); // compute over a box of over 3 standard deviations bool pass = compareSamples(lower, upper, 10, tresult, state.getHistory()); passAll = passAll && pass; if (verbose || !pass) reportPassFail(pass, "Gaussian 2D", "with inferred domain"); // ------------------------------------------------------------ // // next test uses a sub-domain of the first quadrant, the standard deviation is smaller std::fill(tresult.begin(), tresult.end(), 0.3); applyGaussianUpdate(tresult, 0.1, get_rand); // approximate the pdf in regular form, true approximation grid.makeSequenceGrid(2, 1, 24, TasGrid::type_iptotal, TasGrid::rule_rleja); // interpolates exactly all quadratic polynomials grid.getNeededPoints(grid_points); values.resize(grid_points.size() / 2); ip = grid_points.begin(); for(auto &v : values) // using tighter variance of 0.01 v = getDensity(*ip++, 0.3, 0.01) * getDensity(*ip++, 0.3, 0.01); grid.loadNeededPoints(values); // re-initialize the DREAM state state = TasmanianDREAM(num_chains, num_dimensions); initial_set = std::vector(tresult.begin(), tresult.begin() + num_chains * num_dimensions); state.setState(initial_set); lower = std::vector(num_dimensions, 0.0); // consider only the first quadrant upper = std::vector(num_dimensions, 1.0); SampleDREAM(num_burnup, num_iterations, posterior(grid, uniform_prior), hypercube(lower, upper), state, dist_uniform, 0.1, const_percent<98>, // correlated chains [&]()->double{ return unif(park_miller); } ); // check if any of the samples fall outside of the domain pass = compareSamples(lower, upper, 10, tresult, state.getHistory()) && std::none_of(state.getHistory().begin(), state.getHistory().end(), [&](double x)->bool{ return ((x < 0.0) || (x>1.0)); }); passAll = passAll && pass; if (verbose || !pass) reportPassFail(pass, "Gaussian 2D", "with custom domain"); // ------------------------------------------------------------ // // next test uses the same sub-domain of the first quadrant, but the grid and prior each define different dimensions // approximate the pdf in regular form, true approximation grid.makeSequenceGrid(2, 1, 24, TasGrid::type_iptotal, TasGrid::rule_rleja); // interpolates exactly all quadratic polynomials grid.getNeededPoints(grid_points); values.resize(grid_points.size() / 2); ip = grid_points.begin(); for(auto &v : values){ // using tighter variance of 0.01 v = getDensity(*ip++, 0.3, 0.01); ip++; // skip the second dimension in the likelihood } grid.loadNeededPoints(values); // re-initialize the DREAM state state.clearHistory(); initial_set = std::vector(tresult.begin(), tresult.begin() + num_chains * num_dimensions); state.setState(initial_set); SampleDREAM(num_burnup, num_iterations, posterior(grid, [&](TypeSamplingForm, const std::vector &candidates, std::vector &vals)->void{ auto ic = candidates.begin(); for(auto &v : vals){ // using tighter variance of 0.01 ic++; // skip the first dimension in the likelihood v = getDensity(*ic++, 0.3, 0.01); } }), hypercube(lower, upper), state, dist_uniform, 0.1, const_percent<98>, // correlated chains get_rand ); // check if any of the samples fall outside of the domain and if the size of the history is correct pass = compareSamples(lower, upper, 10, tresult, state.getHistory()) && std::none_of(state.getHistory().begin(), state.getHistory().end(), [&](double x)->bool{ return ((x < 0.0) || (x>1.0)); }) && (state.getNumHistory() == (size_t)(num_iterations * num_chains)); passAll = passAll && pass; if (verbose || !pass) reportPassFail(pass, "Gaussian 2D", "with custom prior"); reportPassFail(passAll, "Gaussian 2D", "DREAM-Grid vs Box-Muller"); return passAll; } bool DreamExternalTester::testKnownDistributions(){ // Test Gaussian distribution bool pass1 = testGaussian3D(); bool pass2 = testGaussian2D(); return pass1 && pass2; } bool DreamExternalTester::testCustomModel(){ bool passAll = true; int num_dimensions = 3; int num_samples = 1000, num_chains = 40; int num_iterations = num_samples / num_chains + 2; int num_burnup = 20 * num_iterations; std::minstd_rand park_miller(42); if (usetimeseed) park_miller.seed(getRandomRandomSeed()); std::uniform_real_distribution unif(0.0, 1.0); auto get_rand = [&]()->double{ return unif(park_miller); }; // compute reference samples, means 1.5, 2.0 and 2.5, variance 4.0, 9.0, 4.0 std::vector tresult = genGaussianSamples({1.5, 2.0, 2.5}, {2.0, 3.0, 2.0}, num_samples, get_rand); // Use DREAM with custom model of identity (all information comes form the prior and likelihood) TasmanianDREAM state(num_chains, num_dimensions); std::vector initial_state(num_chains * num_dimensions, 2.0); // initialize with random samples applyGaussianUpdate(initial_state, 3.0, [&]()->double{ return unif(park_miller); }); state.setState(initial_state); LikelihoodGaussIsotropic likely(4.0, {1.5, 2.5}); if (likely.getNumOutputs() != 2) throw std::runtime_error("LikelihoodGaussAnisotropic has wrong num outputs"); SampleDREAM(num_burnup, num_iterations, posterior( [&](const std::vector &candidates, std::vector &values)->void{ // model size_t num_candidates = candidates.size() / 3; auto ic = candidates.begin(); values.resize(2 * num_candidates); auto iv = values.begin(); while(iv != values.end()){ // takes the first and last parameters *iv++ = *ic++; ic++; *iv++ = *ic++; } }, likely, [&](TypeSamplingForm, const std::vector &candidates, std::vector &values)->void{ // prior auto ic = candidates.begin() + 1; // uses the second input entries only for(auto &v : values){ v = getDensity(*ic, 2.0, 9.0); std::advance(ic, num_dimensions); } }), [&](const std::vector&)->bool{ return true; }, // unbounded domain state, [&](std::vector &x){ applyGaussianUpdate(x, 0.5, [&]()->double{ return unif(park_miller); }); }, const_percent<65>, get_rand ); std::vector upper(num_dimensions, 11.0), lower(num_dimensions, -7.0); // compute over a box of more than 3 standard deviations bool pass = compareSamples(lower, upper, 5, tresult, state.getHistory()); passAll = passAll && pass; if (verbose || !pass) reportPassFail(pass, "Inference 3D", "with custom model"); state = TasmanianDREAM(num_chains, num_dimensions); // reinitialize state.setState(genUniformSamples({0.0, 0.0, 0.0}, {1.0, 1.0, 1.0}, num_chains, get_rand)); lower = std::vector(num_dimensions, 0.0); upper = std::vector(num_dimensions, 1.0); likely = LikelihoodGaussIsotropic(0.01, {0.0, 0.0}); SampleDREAM(num_burnup, num_iterations, posterior( [&](const std::vector &candidates, std::vector &values)->void{ // model size_t num_candidates = candidates.size() / 3; values.resize(2 * num_candidates); auto ic = candidates.begin(); auto iv = values.begin(); while(iv != values.end()){ // takes the first and last parameters *iv++ = 1.0 - std::sin(DreamMaths::pi * *ic++); ic++; *iv++ = 1.0 - std::sin(DreamMaths::pi * *ic++); } }, likely, uniform_prior), hypercube(lower, upper), state, dist_gaussian, 0.01, const_percent<50>, get_rand ); std::vector mode; state.getApproximateMode(mode); //cout << mode[0] << " " << mode[1] << " " << mode[2] << " acceptance = " << state.getAcceptanceRate() << endl; pass = ((mode[0] > 0.45) && (mode[0] < 0.55) && (mode[2] > 0.45) && (mode[2] < 0.55) && (state.getAcceptanceRate() > 0.5)); passAll = passAll && pass; if (verbose || !pass) reportPassFail(pass, "Inference 3D", "optimization objective"); reportPassFail(pass, "Inference 3D", "DREAM Bayesian inference"); return passAll; } bool DreamExternalTester::testGridModel(){ bool passAll = true; int num_dimensions = 2, num_outputs = 64; int num_samples = 1000, num_chains = 40; int num_iterations = num_samples / num_chains + 2; int num_burnup = 20 * num_iterations; std::minstd_rand park_miller(42); if (usetimeseed) park_miller.seed(getRandomRandomSeed()); std::uniform_real_distribution unif(0.0, 1.0); auto get_rand = [&]()->double{ return unif(park_miller); }; // Construct sparse grid approximation to the SinSin model std::vector lower = {0.0, 2.0}, upper = {4.0, 6.0}; TasGrid::TasmanianSparseGrid grid; grid.makeLocalPolynomialGrid(num_dimensions, num_outputs, 8, 2); // using quadratic basis of level 4 grid.setDomainTransform(lower, upper); // magnitude is in range (0, 4), frequency in range (2.0, 6.0) std::vector points, values(num_outputs * grid.getNumPoints()); grid.getNeededPoints(points); auto ip = points.begin(), iv = values.begin(); while(ip != points.end()){ getSinSinModel(*ip, *(ip+1), 1.0 / ((double) num_outputs), num_outputs, &*iv); std::advance(ip, num_dimensions); std::advance(iv, num_outputs); } grid.loadNeededPoints(values); // surrogate constructed // initialize the state TasmanianDREAM state(num_chains, grid); state.setState(genUniformSamples(lower, upper, num_chains, get_rand)); // initialize the likelihood std::vector data(num_outputs); getSinSinModel(2.0, 5.0, 1.0 / ((double) num_outputs), num_outputs, data.data()); // true magnitude 2.0, frequency 5.0 LikelihoodGaussIsotropic likely(0.01, data); // sample using uniform prior SampleDREAM(num_burnup, num_chains, posterior(grid, likely, uniform_prior), grid.getDomainInside(), state, dist_gaussian, 0.1, const_percent<50>, get_rand); //printMode(state, "mode"); std::vector mode; state.getApproximateMode(mode); bool pass = ((mode[0] > 1.0) && (mode[0] < 3.0) && (mode[1] > 4.5) && (mode[1] < 5.5)); passAll = passAll && pass; if (verbose || !pass) reportPassFail(pass, "Inference 2D", "grid frequency model"); reportPassFail(pass, "Inference 2D", "DREAM Bayesian grid model"); return passAll; } bool DreamExternalTester::testPosteriorDistributions(){ // Tests using posteriors constructed from model and prior distributions bool pass1 = testCustomModel(); bool pass2 = testGridModel(); return pass1 && pass2; } bool DreamExternalTester::performTests(TypeDREAMTest test){ cout << endl << endl; cout << "---------------------------------------------------------------------" << endl; cout << " Tasmanian DREAM Module: Functionality Test" << endl; cout << "---------------------------------------------------------------------" << endl << endl; bool pass = true; std::vector results(10, 1); // results for all possible tests if ((test == test_all) || (test == test_analytic)) results[0] = (testKnownDistributions()) ? 1 : 0; if ((test == test_all) || (test == test_posterior)) results[1] = (testPosteriorDistributions()) ? 1 : 0; if ((test == test_all) || (test == test_optimization)) results[2] = (testOptimization()) ? 1 : 0; pass = std::all_of(results.begin(), results.end(), [&](int i)->bool{ return (i == 1); }); cout << endl; if (pass){ cout << "---------------------------------------------------------------------" << endl; cout << " All Tests Completed Successfully" << endl; cout << "---------------------------------------------------------------------" << endl << endl; }else{ cout << "FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL" << endl; cout << " Some Tests Have Failed" << endl; cout << "FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL" << endl << endl; } return pass; } void testDebug(){ cout << "Debug Test" << endl; cout << "Put here testing code and call this with ./dreamtest debug" << endl; } #endif TASMANIAN-8.1/DREAM/tasdreamExternalTests.hpp000066400000000000000000000246541470551176200206070ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_TASDREAM_EXTERNAL_TESTS_HPP #define __TASMANIAN_TASDREAM_EXTERNAL_TESTS_HPP #include "TasmanianDREAM.hpp" #include "Optimization/TasmanianOptimization.hpp" using std::cout; using std::cerr; using std::endl; using std::setw; using namespace TasDREAM; //! \internal //! \defgroup TasDREAMTesting: Testing for the Tasmanian DREAM module. //! //! \par Testing //! A series of tests covering sampling under different circumstances, //! sample from arbitrary distribution, perform Bayesian inference on //! a model (custom or defined by a sparse grid), or solve an optimization //! problem. //! \internal //! \brief Allows to select a specific category for testing. //! \ingroup TasDREAMTesting enum TypeDREAMTest{ //! \brief Execute all tests. test_all, //! \brief Tests for sampling from known probability density. test_analytic, //! \brief Tests for sampling from posterior distributions. test_posterior, //! \brief Tests for function optimization states and algorithms. test_optimization }; //! \internal //! \brief Report Pass/FAIL bases on pass, format is "name Pass/FAIL". //! \ingroup TasDREAMTesting inline void reportPassFail(bool pass, const char *name){ cout << setw(45) << name << setw(15) << ((pass) ? "Pass" : "FAIL") << endl; } //! \internal //! \brief Report Pass/FAIL bases on pass, format is "name variant Pass/FAIL" //! \ingroup TasDREAMTesting inline void reportPassFail(bool pass, const char *name, const char *variant){ cout << setw(20) << name << setw(30) << variant << setw(15) << ((pass) ? "Pass" : "FAIL") << endl; } //! \internal //! \brief Get a random number to be used for a random seed, uses \b std::time(\b nullptr). //! \ingroup TasDREAMTesting inline long unsigned getRandomRandomSeed(){ return static_cast(std::time(nullptr)); } //! \internal //! \brief Dump the history of the state to \b cout using one point per line (debug use only). //! \ingroup TasDREAMTesting inline void printHistory(const TasmanianDREAM &state){ const std::vector &hist = state.getHistory(); const std::vector &vals = state.getHistoryPDF(); int num_dimensions = state.getNumDimensions(); auto ih = hist.begin(); cout << std::scientific; cout.precision(6); for(auto v : vals){ for(int i=0; i mean, variance; state.getHistoryMeanVariance(mean, variance); if (message != nullptr) cout << message << endl; cout << std::scientific; cout.precision(6); for(auto m : mean) cout << m << " "; cout << endl; for(auto v : variance) cout << std::sqrt(v) << " "; cout << endl; } //! \internal //! \brief Print the approximate mode from the history. //! \ingroup TasDREAMTesting inline void printMode(const TasmanianDREAM &state, const char *message = nullptr){ std::vector mode; state.getApproximateMode(mode); if (message != nullptr) cout << message << endl; cout << std::scientific; cout.precision(6); for(auto m : mode) cout << m << " "; cout << endl; } //! \internal //! \brief Simple model of a signal with two overlapping frequencies. //! \ingroup TasDREAMTesting //! The model is \f$ f(t) = \sin(\pi t) + M \sin( F \pi t) \f$ where M is the \b magnitude and F is the \b frequency. //! The result is sampled for t in (\b time_step, \b num_steps * \b time_step) resulting in a vector of length \b num_steps. //! The entries are written to the array \b y. inline void getSinSinModel(double magnitude, double frequency, double time_step, int num_steps, double *y){ double t = time_step; for(int i=0; i &cell_count_a, const std::vector &cell_count_b); //! \brief Bin hypercube data. //! Takes \b data that represents vectors of dimensions \b lower.size() that lay in hypercube defined by \b lower and \b upper limits, //! the data is binned into uniform cell grid with 1-D size \b num_bins1D. void binHypercubeSamples(const std::vector &lower, const std::vector &upper, int num_bins1D, const std::vector &data, std::vector &bin_count); //! \brief Test if sample follow the same distribution, calls \b binHypercubeSamples() and \b testFit(). bool compareSamples(const std::vector &lower, const std::vector &upper, int num_bins1D, const std::vector &data1, const std::vector &data2); private: bool verbose, showvalues, usetimeseed; }; //! \internal //! \brief Normally an empty function, but the user can put code inside for quick testing. //! Performance, debug, and other tests of a library require that client code is written and linked to the library, //! which require a separate project with source files, build system, etc. //! This function offers an easy way to compile additional code using the default Tasmanian build engine, //! the code can be invoked from the root of the build folder using: //! \code ./DREAM/dreamtest -debug \endcode //! The function is implemented at the very bottom of \b tasdreamExternalTests.cpp. void testDebug(); #endif TASMANIAN-8.1/DREAM/tsgDreamCorePDF.hpp000066400000000000000000000145061470551176200171650ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_CORE_PDF_HPP #define __TASMANIAN_DREAM_CORE_PDF_HPP /*! * \internal * \file tsgDreamCorePDF.hpp * \brief Gives the unscaled formulas for several probability distributions. * \author Miroslav Stoyanov * \ingroup TasmanianDREAM * \endinternal */ #include "tsgDreamEnumerates.hpp" namespace TasDREAM{ //! \brief Returns the unscaled probability density of \b distribution (defined by \b params) at the point \b x. //! \ingroup DREAMPDF //! Variadric template that defines different one dimensional probability density function. //! Each function is defined by the \b distribution type and a set of parameters \b params, //! but the densities are not normalized (this is not needed by the DREAM algorithm). //! \b Returns the value of the density function at \b x, but \b assumes \b x \b is \b in \b the \b domain, //! i.e., if the probability distribution is restricted to an interval no check is performed. //! For example, for uniform distribution over (a, b), the function will always return 1. //! //! Both the regular and log-form of the density can be computed based on \b form. //! //! \par Uniform distribution, dist_uniform, //! No additional parameters are needed, always returns 1, e.g., //! \code double foo = getDensity(0.2); // foo will be 1.0 \endcode //! //! \par Gaussian distribution, dist_gaussian //! Uses two parameters, mean and variance, defined in that order, e.g., //! \code double y = getDensity(x, M, V); \endcode //! then \f$ y = \exp(- 0.5 (x - M)^2 / V) \f$. //! Note that this also works for truncated Gaussian distribution, since the range and scale are not considered. //! //! \par Exponential distribution, dist_exponential //! Uses two parameters, lower bound and rate (or inverse scale), e.g., //! \code double y = getDensity(x, x0, R); \endcode //! then \f$ y = \exp(- R * (x - x_0)) \f$. //! //! \par Beta distribution, dist-beta //! Uses four parameters, lower and upper bounds and two shapes, e.g., //! \code double y = getDensity(x, x0, x1, alpha, beta); \endcode //! then \f$ y = (x - x_0)^{\alpha - 1} (x_1 - x_0)^{\beta - 1} \f$. //! //! \par Gamma distribution, dist-beta //! Uses three parameters, lower bounds, shape and rate, e.g., //! \code double y = getDensity(x, x0, alpha, beta); \endcode //! then \f$ y = (x - x_0)^{\alpha - 1} \exp(-\beta (x - x_0)) \f$. //! template double getDensity(double x, Params... params){ std::vector>::type> ParameterArray = {params...}; if (form == regform){ if (distribution == dist_gaussian){ return std::exp(-0.5 * (x - ParameterArray[0]) * (x - ParameterArray[0]) / ParameterArray[1]); }else if (distribution == dist_exponential){ return std::exp(-ParameterArray[1] * (x - ParameterArray[0])); }else if (distribution == dist_beta){ return std::pow(x - ParameterArray[0], ParameterArray[2] - 1.0) * std::pow(ParameterArray[1] - x, ParameterArray[3] - 1.0); }else if (distribution == dist_gamma){ return std::pow(x - ParameterArray[0], ParameterArray[1] - 1.0) * std::exp(- ParameterArray[2] * (x - ParameterArray[0])); }else{ // uniform return 1.0; } }else{ if (distribution == dist_gaussian){ return -0.5 * (x - ParameterArray[0]) * (x - ParameterArray[0]) / ParameterArray[1]; }else if (distribution == dist_exponential){ return -ParameterArray[1] * (x - ParameterArray[0]); }else if (distribution == dist_beta){ return std::log(x - ParameterArray[0]) * (ParameterArray[2] - 1.0) + std::log(ParameterArray[1] - x) * (ParameterArray[3] - 1.0); }else if (distribution == dist_gamma){ return std::log(x - ParameterArray[0]) * (ParameterArray[1] - 1.0) - ParameterArray[2] * (x - ParameterArray[0]); }else{ // uniform return 0.0; } } } } #endif TASMANIAN-8.1/DREAM/tsgDreamCoreRandom.hpp000066400000000000000000000172061470551176200177740ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_CORE_RANDOM_HPP #define __TASMANIAN_DREAM_CORE_RANDOM_HPP /*! * \internal * \file tsgDreamCoreRandom.hpp * \brief Core random sampling methods * \author Miroslav Stoyanov * \ingroup TasmanianDREAM * \internal * * Implements several methods for random sampling and defines specific probability density functions. * \endinternal */ /*! * \ingroup TasmanianDREAM * \addtogroup DREAMPDF Probability distributions, analytic formulas and sampling algorithms * * Contains the analytic definitions of several probability distributions * and algorithms to draw samples from several known distributions. */ namespace TasDREAM{ //! \internal //! \brief Default random sampler, using \b rand() divided by \b RAND_MAX //! \ingroup DREAMPDF //! Generates random numbers uniformly distributed in (0, 1), uses the \b rand() command. inline double tsgCoreUniform01(){ return ((double) rand()) / ((double) RAND_MAX); } //! \brief Add a correction to every entry in \b x, use uniform samples over (-\b magnitude, \b magnitude). //! \ingroup DREAMPDF //! The function \b get_random01() returns random numbers distributed over (0, 1). inline void applyUniformUpdate(std::vector &x, double magnitude, std::function get_random01 = tsgCoreUniform01){ if (magnitude == 0.0) return; for(auto &v : x) v += magnitude * (2.0 * get_random01() -1.0); } //! \brief Add a correction to every entry in \b x, sue Gaussian distribution with zero mean and standard deviation equal to \b magnitude. //! \ingroup DREAMPDF //! The function \b get_random01() returns random numbers distributed over (0, 1). //! Gaussian numbers are generated using the Box-Muller algorithm. inline void applyGaussianUpdate(std::vector &x, double magnitude, std::function get_random01 = tsgCoreUniform01){ if (magnitude == 0.0) return; bool tictoc = false; double g = 0.0; for(auto &v : x){ tictoc = !tictoc; if (tictoc){ double r = magnitude * std::sqrt(-2.0 * std::log(get_random01())), t = 2.0 * DreamMaths::pi * get_random01(); // radius and angle v += r * std::cos(t); g = r * std::sin(t); }else{ v += g; } } } //! \brief Generate uniform random samples in the hypercube defined by \b lower and \b upper limits. //! \ingroup DREAMPDF //! The size of the \b lower and \b upper must match. //! The output vector \b x will be resized to match \b num_samples times \b upper.size(), and the values will be overwritten. //! The function \b get_random01() returns random numbers distributed over (0, 1). inline void genUniformSamples(const std::vector &lower, const std::vector &upper, int num_samples, std::vector &x, std::function get_random01 = tsgCoreUniform01){ if (lower.size() != upper.size()) throw std::runtime_error("ERROR: genUniformSamples() requires lower and upper vectors with matching size."); if (x.size() != lower.size() * num_samples) x.resize(lower.size() * num_samples); for(auto &v : x) v = get_random01(); std::vector length(lower.size()); std::transform(lower.begin(), lower.end(), upper.begin(), length.begin(), [&](double l, double u)->double{ return (u - l); }); auto ix = x.begin(); while(ix != x.end()){ auto ilow = lower.begin(); for(auto l : length){ *ix *= l; *ix++ += *ilow++; } } } /*! * \ingroup DREAMPDF * \brief Overload that returns the vector. */ inline std::vector genUniformSamples(const std::vector &lower, const std::vector &upper, int num_samples, std::function get_random01 = tsgCoreUniform01){ std::vector x; genUniformSamples(lower, upper, num_samples, x, get_random01); return x; } //! \brief Generate standard normal samples with given \b means and standard \b deviations. //! \ingroup DREAMPDF //! Generate Gaussian (normal) vectors with given means and standard deviations. //! The \b means and \b deviations must have the same size. //! The function \b get_random01() returns random numbers distributed over (0, 1). inline void genGaussianSamples(const std::vector &means, const std::vector &deviations, int num_samples, std::vector &x, std::function get_random01 = tsgCoreUniform01){ if (means.size() != deviations.size()) throw std::runtime_error("ERROR: genGaussianSamples() means and deviations vectors must have the same size."); if (x.size() != means.size() * num_samples) x.resize(means.size() * num_samples); std::fill_n(x.data(), x.size(), 0.0); applyGaussianUpdate(x, 1.0, get_random01); auto ix = x.begin(); while(ix != x.end()){ auto im = means.begin(); for(auto s : deviations){ *ix *= s; *ix++ += *im++; } } } /*! * \ingroup DREAMPDF * \brief Overload that returns the vector. */ inline std::vector genGaussianSamples(const std::vector &means, const std::vector &deviations, int num_samples, std::function get_random01 = tsgCoreUniform01){ std::vector x; genGaussianSamples(means, deviations, num_samples, x, get_random01); return x; } } #endif TASMANIAN-8.1/DREAM/tsgDreamEnumerates.hpp000066400000000000000000000155261470551176200200560ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_ENUMERATES_HPP #define __TASMANIAN_DREAM_ENUMERATES_HPP #include #include "TasmanianSparseGrid.hpp" /*! * \internal * \file tsgDreamEnumerates.hpp * \brief The enumerated types used in the DREAM module. * \author Miroslav Stoyanov * \ingroup TasmanianDREAM * * Defines the enumerated types used throughout the DREAM module. * The file is included in every other DREAM header. * \endinternal */ /*! * \ingroup TasmanianDREAM * \addtogroup DREAMEnumerates Enumerated types * * The Enumerate types used in the external and internal API of the DREAM module. */ namespace TasDREAM{ /*! * \internal * \ingroup TasmanianDREAM * \addtogroup DREAMUtils Miscellaneous utility templates, borrowed from TasGrid. * * Several templates borrowed from the Sparse Grids module and included here for easier usage. * \endinternal */ /*! * \internal * \ingroup DREAMUtils * * Similar to TasGrid::Utils this holds aliases to size_mult(), TasGrid::Utils::Wrapper2D, and copyArray(). * \endinternal */ namespace Utils{ //! \brief See TasGrid::Utils::size_mult(). using TasGrid::Utils::size_mult; //! \brief See TasGrid::Utils::Wrapper2D. using TasGrid::Utils::Wrapper2D; //! \brief See TasGrid::Utils::copyArray(). using TasGrid::Utils::copyArray; } //! \brief Describes whether sampling should be done with the regular or logarithm form of the probability density. //! \ingroup DREAMEnumerates //! Probability distributions with very localized support will have values close to zero over most of the sampling domain. //! Sampling using the logarithm of the probability density can be more stable, when operations with very small numbers cause problems. //! In most cases, it is up to the user to provide the appropriate values, but the sampling algorithm needs to know which form is being used. enum TypeSamplingForm{ //! \brief Use the standard form for the probability density. regform, //! \brief Use the logarithm form for the probability density. logform }; //! \brief Indicates a specific probability distribution for the associated function. //! \ingroup DREAMEnumerates //! Used to instantiate the \b getDensity() variadric template. See the template documentation for the specific formulas. enum TypeDistribution{ //! \brief Uniform distribution. dist_uniform, //! \brief Gaussian or Normal distribution defined by mean and variance. dist_gaussian, //! \brief Exponential distribution (i.e., special case of the Gamma distribution). dist_exponential, //! \brief Beta distribution, corresponds to Gauss-Jacobi sparse grid rule \b TasGrid::rule_gaussjacobi. dist_beta, //! \brief Gamma distribution, corresponds to Gauss-Laguerre sparse grid rule \b TasGrid::rule_gausslaguerre. dist_gamma, //! \brief Indicates a no-distribution (no correction). dist_none, //! \brief Indicates I/O error or unspecified distribution. dist_null }; /*! * \internal * \ingroup DREAMUtils * \brief Similar to TasGrid::IO this holds conversion methods between enums and int/string types. * * \endinternal */ namespace IO{ /*! * \internal * \ingroup TasmanianIO * \brief Converts an integer to TypeSamplingForm, synced with the Python interface. * * \endinternal */ inline TypeSamplingForm intToForm(int form){ return (form == 0) ? regform : logform; } /*! * \internal * \ingroup TasmanianIO * \brief Returns the map from a string to a distribution type. * * \endinternal */ inline std::map getStringRuleMap(){ return std::initializer_list>{ {"null", dist_null}, {"none", dist_none}, {"uniform", dist_uniform}, {"gaussian", dist_gaussian}, {"exponential", dist_exponential}, {"beta", dist_beta}, {"gamma", dist_gamma}}; } /*! * \internal * \ingroup TasmanianIO * \brief Map the string distribution name to the enumerate, used by python. * * \endinternal */ inline TypeDistribution getDistributionString(std::string const &name){ try{ return getStringRuleMap().at(name); }catch(std::out_of_range &){ return dist_null; } } } namespace DreamMaths{ /*! * \internal * \ingroup DREAMEnumerates * \brief Dream copy of \b TasGrid::Maths::pi. * * \endinternal */ constexpr double pi = TasGrid::Maths::pi; } } #endif TASMANIAN-8.1/DREAM/tsgDreamLikelihoodCore.hpp000066400000000000000000000130101470551176200206240ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_LIKELY_CORE_HPP #define __TASMANIAN_DREAM_LIKELY_CORE_HPP #include "tsgDreamEnumerates.hpp" /*! * \internal * \file tsgDreamLikelihoodCore.hpp * \brief The interface mother-class for the likelihood classes. * \author Miroslav Stoyanov * \ingroup TasmanianDREAM * * Defines the TasmanianLikelihood class which implements the relation between model outputs and measurement data. * \endinternal */ /*! * \ingroup TasmanianDREAM * \addtogroup DREAMLikelihood Likelihood definitions * * Classes that define the likelihood relation between an observed data and a model output. */ namespace TasDREAM{ //! \brief Interface for the likelihood classes. //! \ingroup DREAMLikelihood //! \par Likelihood //! In the framework of Bayesian inference the likelihood is a measure of how likely is a specific outcome (i.e., model output), given some observed data. //! The likelihood class (usually) contains the data and implements a specific formula that measure the discrepancy. //! The \b TasmanianLikelihood class is virtual, but an inherited class is required for the \b SampleDREAMPosterior() methods. //! //! \par Included Likelihood Formulas //! The chose of likelihood is very problem dependent and Tasmanian implements only a few commonly used cases, //! mostly relying on the assumption that the data is contaminated with white noise. //! However, the user can implement any other likelihood by simply inheriting from this class. class TasmanianLikelihood{ public: //! \brief Empty default constructor. TasmanianLikelihood(){} //! \brief Empty virtual destructor. virtual ~TasmanianLikelihood(){} //! \brief Purely virtual method used by \b SampleDREAMPosterior(), computes the likelihood of multiple model values. //! The \b model vector is the same as the output of the model lambda in \b SampleDREAMPosterior() or the \b TasGrid::TasmanianSparseGrid::evaluateBatch(), //! the model realizations are stored contiguously in strides of length equal to the number of model outputs. //! The \b likely vector is pre-allocated with size matching the number of model realizations under considerations (no resize is needed), //! this function must populate the \b likely entries with the corresponding values of the likelihood. //! Note that model.size() / likely.size() will divide evenly and will equal the number of model realizations. virtual void getLikelihood(TypeSamplingForm form, const std::vector &model, std::vector &likely) const = 0; //! \brief Overload for raw-arrays, for interface purposes mostly, never called from C++ directly. virtual void getLikelihood(TypeSamplingForm form, double const model[], int num_samples, double likely[]) const = 0; //! \brief Return the number of expected model outputs. virtual int getNumOutputs() const = 0; //! \brief Automatically convert the likelihood into input for TasDREAM::posterior(). virtual operator std::function &, std::vector &)>() const{ return [&](TypeSamplingForm form, const std::vector &model, std::vector &likely)->void{ getLikelihood(form, model, likely); }; }; }; } #endif TASMANIAN-8.1/DREAM/tsgDreamLikelyGaussian.cpp000066400000000000000000000160171470551176200206610ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_LIKELY_GAUSS_CPP #define __TASMANIAN_DREAM_LIKELY_GAUSS_CPP #include "tsgDreamLikelyGaussian.hpp" #ifdef Tasmanian_ENABLE_BLAS #include "tsgBlasWrappers.hpp" #endif namespace TasDREAM{ void LikelihoodGaussIsotropic::setData(double variance, const std::vector &data_mean, size_t num_observe){ if (variance <= 0.0) throw std::runtime_error("ERROR: LikelihoodGaussIsotropic, should have positive varience."); if (data_mean.empty()) throw std::runtime_error("ERROR: LikelihoodGaussIsotropic, emptry data vector."); data = data_mean; scale = -0.5 * double(num_observe) / variance; } void LikelihoodGaussIsotropic::getLikelihood(TypeSamplingForm form, const std::vector &model, std::vector &likely) const{ getLikelihood(form, model.data(), (int) (model.size() / data.size()), likely.data()); } void LikelihoodGaussIsotropic::getLikelihood(TypeSamplingForm form, double const model[], int num_samples, double likely[]) const{ int num_outputs = (int) data.size(); Utils::Wrapper2D wrapped_model(num_outputs, model); #ifdef Tasmanian_ENABLE_BLAS for(int i=0; i const &variance, std::vector const &data_mean, size_t num_observe){ if (variance.size() != data_mean.size()) throw std::invalid_argument("ERROR: LikelihoodGaussAnisotropic, should have variance and data with same size."); double scale = -0.5 * double(num_observe); noise_variance = std::vector(variance.size()); data_by_variance = std::vector(variance.size()); for(size_t i=0; i const &model, std::vector &likely) const{ getLikelihood(form, model.data(), (int) (model.size() / data_by_variance.size()), likely.data()); } void LikelihoodGaussAnisotropic::getLikelihood(TypeSamplingForm form, double const model[], int num_samples, double likely[]) const{ int num_outputs = (int) data_by_variance.size(); Utils::Wrapper2D wrapped_model(num_outputs, model); #ifdef Tasmanian_ENABLE_BLAS for(int i=0; i(data, data + num_outputs), (size_t) num_samples); } void *tsgMakeLikelihoodGaussAnisotropic(int num_outputs, double const variance[], double const data[], int num_samples){ return (void*) new LikelihoodGaussAnisotropic(std::vector(variance, variance + num_outputs), std::vector(data, data + num_outputs), (size_t) num_samples); } void tsgGetLikelihood(void *likelihood, int form, double const model[], int num_samples, double likely[]){ ((TasmanianLikelihood*) likelihood)->getLikelihood(IO::intToForm(form), model, num_samples, likely); } int tsgGetNumOutputsLikelihood(void *likelihood){ return ((TasmanianLikelihood*) likelihood)->getNumOutputs(); } void tsgDeleteLikelihood(void *likelihood){ delete ((TasmanianLikelihood*) likelihood); } } } #endif TASMANIAN-8.1/DREAM/tsgDreamLikelyGaussian.hpp000066400000000000000000000254221470551176200206660ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_LIKELY_GAUSS_HPP #define __TASMANIAN_DREAM_LIKELY_GAUSS_HPP #include "tsgDreamLikelihoodCore.hpp" /*! * \internal * \file tsgDreamLikelyGaussian.hpp * \brief Several likelihood implementations based on Gaussian noise. * \author Miroslav Stoyanov * \ingroup TasmanianDREAM * \endinternal */ namespace TasDREAM{ //! \brief Implements likelihood under the assumption of isotropic white noise. //! \ingroup DREAMLikelihood //! \par Gaussian Likelihood //! The general formula for Gaussian likelihood is \f$ L(y | d_1 \cdots d_n) = \exp\left( 0.5 sum_{i=1}^n (y - d_i)^T \Sigma^{-1} (y - d_i) \right)\f$ //! where the \f$ d_i \f$ are the data observations, \b y is the model output, and \f$ \Sigma \f$ is the noise covariance matrix. //! //! \par Isotropic Gaussian //! The simplest isotopic case of Gaussian likelihood assumes that the covariance matrix is scaled identity, //! i.e., the noise has no correlation and has the same magnitude for each model output, //! then inverting the covariance matrix reduces to multiplying by the inverse of the noise variance (magnitude). //! Also, the sum corresponding to the multiple data samples can be replaced by scaled operation on the data mean (average). class LikelihoodGaussIsotropic : public TasmanianLikelihood{ public: //! \brief Default constructor for convenience, an object constructed with the default cannot be used until \b setData() is called. LikelihoodGaussIsotropic() : scale(0.0){} //! \brief Constructs the class and calls \b setData(). LikelihoodGaussIsotropic(double variance, const std::vector &data_mean, size_t num_observe = 1){ setData(variance, data_mean, num_observe); } //! \brief Default destructor. ~LikelihoodGaussIsotropic() = default; /*! * \brief Set the noise magnitude (\b varaince) the observed data (\b data_mean) and number of observations (\b num_observe). * * Set the parameters of the likelihood. * \param variance must be a positive number indicating the magnitude of the noise. * \param data_mean must have the same size as the number of model outputs and hold * the average of all measurements. * \param num_observe must be a positive integer indicating the number of samples. */ void setData(double variance, const std::vector &data_mean, size_t num_observe = 1); //! \brief Compute the likelihood of a set of model outputs. void getLikelihood(TypeSamplingForm form, const std::vector &model, std::vector &likely) const override final; //! \brief Overload for raw-arrays, for interface purposes mostly, e.g., python. void getLikelihood(TypeSamplingForm form, double const model[], int num_samples, double likely[]) const override final; //! \brief Returns the size of the \b data_mean vector (for error checking purposes). int getNumOutputs() const override{ return (int) data.size(); } /*! * \brief Writes the data for a portion of the outputs into a stream. * * The likelihood object does not store the raw inputs to setData(), instead optimized data-structures are used. * This method writes either entire likelihood or the optimized data for a portion of the outputs. * * \param os is the stream where the data will be written. * \param outputs_begin is the first output to include in the write process. * \param outputs_end is one more than the last output to write, * use -1 to indicate all outputs after \b output_begin. * * This method is used by the MPI scatter likelihood template. */ void write(std::ostream &os, int outputs_begin = 0, int outputs_end = -1) const{ if (outputs_end < 0) outputs_end = getNumOutputs(); outputs_end = std::min(std::max(outputs_begin + 1, outputs_end), getNumOutputs()); int num_entries = outputs_end - outputs_begin; TasGrid::IO::writeNumbers(os, num_entries); TasGrid::IO::writeNumbers(os, scale); os.write((char*) &data[outputs_begin], num_entries * sizeof(double)); } //! \brief Reads the data from a stream, assumes write() has been used first. void read(std::istream &is){ int num_entries = TasGrid::IO::readNumber(is); scale = TasGrid::IO::readNumber(is); data = std::vector((size_t) num_entries); TasGrid::IO::readVector(is, data); } private: std::vector data; double scale; }; /*! * \brief Implements likelihood under the assumption of anisotropic white noise. * \ingroup DREAMLikelihood * * \par Gaussian Likelihood * The general formula for Gaussian likelihood is \f$ L(y | d_1 \cdots d_n) = \exp\left( 0.5 sum_{i=1}^n (y - d_i)^T \Sigma^{-1} (y - d_i) \right)\f$ * where the \f$ d_i \f$ are the data observations, \b y is the model output, and \f$ \Sigma \f$ is the noise covariance matrix. * * \par Anisotropic Gaussian * A more advanced version of the Gaussian likelihood associated each model output * with noise of different magnitude. The inversion of the covariance reduces to * division of each input by the corresponding magnitude * (i.e., there is no matrix inversion). * Similarly to the simple case, the sum corresponding to the multiple data samples * can be replaced by scaled operation on the data mean (average). */ class LikelihoodGaussAnisotropic : public TasmanianLikelihood{ public: //! \brief Default constructor for convenience, an object constructed with the default cannot be used until \b setData() is called. LikelihoodGaussAnisotropic() = default; //! \brief Constructs the class and calls \b setData(). LikelihoodGaussAnisotropic(std::vector const &variance, std::vector const &data_mean, size_t num_observe = 1){ setData(variance, data_mean, num_observe); } //! \brief Default destructor. ~LikelihoodGaussAnisotropic() = default; /*! * \brief Set the noise magnitude (\b variance) the observed data (\b data_mean) and number of observations (\b num_observe). * * \param variance is a vector with size equal to the number of model outputs. * Each entry represents the noise magnitude (variance) associated with that output. * \param data_mean is the average of all available observations of the data. * \param num_observe is the number of observations used to compute the \b data_mean. */ void setData(std::vector const &variance, std::vector const &data_mean, size_t num_observe = 1); //! \brief Compute the likelihood of a set of model outputs. void getLikelihood(TypeSamplingForm form, std::vector const &model, std::vector &likely) const override final; //! \brief Overload for raw-arrays, for interface purposes mostly, e.g., python. void getLikelihood(TypeSamplingForm form, double const model[], int num_samples, double likely[]) const override final; //! \brief Returns the size of the \b data_mean vector (for error checking purposes). int getNumOutputs() const override{ return (int) noise_variance.size(); } /*! * \brief Writes the data for a portion of the outputs into a stream. * * See LikelihoodGaussIsotropic::write(). */ void write(std::ostream &os, int outputs_begin = 0, int outputs_end = -1) const{ if (outputs_end < 0) outputs_end = getNumOutputs(); outputs_end = std::min(std::max(outputs_begin + 1, outputs_end), getNumOutputs()); int num_entries = outputs_end - outputs_begin; TasGrid::IO::writeNumbers(os, num_entries); os.write((char*) &data_by_variance[outputs_begin], num_entries * sizeof(double)); os.write((char*) &noise_variance[outputs_begin], num_entries * sizeof(double)); } //! \brief Reads the data from a stream, assumes write() has been used first. void read(std::istream &is){ int num_entries = TasGrid::IO::readNumber(is); data_by_variance = std::vector((size_t) num_entries); noise_variance = std::vector((size_t) num_entries); TasGrid::IO::readVector(is, data_by_variance); TasGrid::IO::readVector(is, noise_variance); } private: std::vector data_by_variance; std::vector noise_variance; }; } #endif TASMANIAN-8.1/DREAM/tsgDreamSample.hpp000066400000000000000000000675261470551176200171760ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_SAMPLE_HPP #define __TASMANIAN_DREAM_SAMPLE_HPP #include "tsgDreamState.hpp" #include "tsgDreamCoreRandom.hpp" #include "tsgDreamCorePDF.hpp" /*! * \internal * \file tsgDreamSample.hpp * \brief Core sampling templates. * \author Miroslav Stoyanov * \ingroup TasmanianDREAM * * Defines the core MCMC template for sampling from an arbitrarily defined unscaled probability density. * \endinternal */ /*! * \ingroup TasmanianDREAM * \addtogroup DREAMSampleCore DREAM Sampling Templates * * Templates and auxiliary methods for the DREAM sampling. * The main template is TasDREAM::SampleDREAM() with one overload * and several helper functions. * The helpers provide ways to define the probability distribution: * either custom defined, interpolated with a sparse grid, or product of Bayesian inference problem. */ namespace TasDREAM{ /*! * \ingroup DREAMSampleCore * \brief Generic test function whether a sample belongs in the domain. * * The function accepts a single vector with size equal to the number of domain dimensions * and must return \b true if the vector belongs to the domain or \b false otherwise. */ using DreamDomain = std::function const &x)>; /*! * \ingroup DREAMSampleCore * \brief Make a lambda that matches the \b inside signature in \b SampleDREAM(), test if the vector x is in the hyperbube described by \b lower and \b upper. */ inline DreamDomain hypercube(std::vector const &lower, std::vector const &upper){ return [=](const std::vector &x)->bool{ auto il = lower.begin(), iu = upper.begin(); for(auto v : x) if ((v < *il++) || (v > *iu++)) return false; return true; }; } /*! * \ingroup DREAMSampleCore * \brief Dummy function that does not make any changes to the vector as default for the \b independent_update() in \b SampleDREAM(). * * The function is no-op. */ inline void no_update(std::vector &){} /*! * \brief Dummy function that returns 1.0, used as default for the \b differential_update() in \b SampleDREAM(). * \ingroup DREAMSampleCore * * Just an inline function that returns 1.0. */ inline double const_one(){ return 1.0; } /*! * \brief Template that returns a constant based on the percentage, i.e., \b weight_percent / 100.0 * \ingroup DREAMSampleCore * * The template simplifies the syntax when calling \b SampleDREAM() with a constant differential update. * For example, setting the update to 0.5 can be done with * \code * TasmanianDREAM state(...); * SampleDREAM(..., independent_update, const_percent<50>, state); * \endcode */ template double const_percent(){ return ((double) weight_percent) / 100.0; } /*! * \brief Uniform prior distribution for both regular and log form. * \ingroup DREAMSampleCore * * Applies uniform (non-informative) prior, can be used with any of the Bayesian inference methods. * In practice, this actually does nothing, since adding zero (in \b logform) or mulitplying by 1 (in \b regform) amounts to nothing. */ inline void uniform_prior(TypeSamplingForm, const std::vector &, std::vector &values){ values.clear(); } /*! * \ingroup DREAMSampleCore * \brief Generic probability distribution used by Tasmanian. * * The probability distribution must be set to accept multiple candidates and return * the value of the unscaled probability distribution for each point. * * \param candidates is a vector with size that is an even multiple of the dimensions, * the vector is organized logically into strips of size num-dimensions. * Each strip represents a test point that is guaranteed to be inside the domain. * \param values is a vector with size equal to the number of strips (samples) in \b candidates. * The vector should not be resized, instead each value has to be overwritten * with the corresponding unscaled probability distribution. * * \b Note: the generic probability distribution does not accept a parameter to specify the sampling * form, e.g., TasDREAM::logform. The returned values \b must corresponding to the sampling * form set in the TasDREAM::SampleDREAM() template. If logarithm form is used, the values * can be negative, in regular form the values must be positive, Tasmanian will not throw * an exception but using negative values with TasDREAM::regform leads to undefined behavior. */ using DreamPDF = std::function &candidates, std::vector &values)>; /*! * \ingroup DREAMSampleCore * \brief Generic model signature used by Tasmanian. * * The model is very similar to the TasDREAM::DreamPDF, in fact the input \b candidates is the same. * The differences are two: * - the model may have multiple outputs and the number of returned outputs must match * the number of outputs used by the likelihood. * - the \b outputs vector will not be set to the correct size, it \b must be resized, * because Tasmanian does not keep track of the number of outputs. * * \b Note: the \b outputs vector will be fed as input to the TasDREAM::DreamLikelihood. */ using DreamModel = std::function &candidates, std::vector &outputs)>; /*! * \ingroup DREAMSampleCore * \brief Generic likelihood signature used by Tasmanian. * * The likelihood assigns a value to how likely the model outputs are given data (i.e., measurements). * Classes that inherit TasmanianLikelihood will automatically convert to a lambda object with * this signature. * * \param form is the sampling type used in the call to TasDREAM::SampleDREAM(), in a custom object * it is sufficient to implement only one form, Tasmanian likelihood classes implement both * and thus the parameter specifies which implementation to use. * \param model_outputs is identical to \b outputs parameter in TasDREAM::DreamModel * except here it is used as an input to compute the likelihood. * \param likely is a vector with size equal to the entries with \b outputs, * the entries must be overwritten with the corresponding likelihood. */ using DreamLikelihood = std::function &model_outputs, std::vector &likely)>; /*! * \ingroup DREAMSampleCore * \brief Generic signature for the prior distributions used by Tasmanian. * * Specifies the prior distribution, the TasDREAM::uniform_prior() satisfies this signature. * \param form is the same as in TasDREAM::DreamLikelihood. * \param candidates is the same as in TasDREAM::DreamModel and TasDREAM::DreamPDF. * \param values are similar to the \b likely in TasDREAM::DreamLikelihood, but instead of the likelihood * the values define the prior distribution in the specified \b form. */ using DreamPrior = std::function &candidates, std::vector &values)>; /*! * \ingroup DREAMSampleCore * \brief Generic signature for a combination of a likelihood and a model. * * The likelihood and the model are not always separated, e.g., a sparse grid * approximation can be used to interpolated the likelihood which has a single output * and is therefore cheaper than interpolating multi-output model. * The implementation should be equivalent to: * \param candidates is same as in TasDREAM::DreamModel. * \param values is same as in TasDREAM::DreamLikelihood \b likely parameter. */ using DreamMergedLikelyModel = std::function &candidates, std::vector &values)>; /*! * \ingroup DREAMSampleCore * \brief Combines the three components of a Bayesian posterior into a single distribution. * * The Bayesian posterior has a model, likelihood function and a prior distribution. * This function combines three function objects into a single probability distribution * that be passed to SampleDREAM, e.g., * \code * SampleDREAM(num_burnup, num_collect, posterior(likely, model, uniform_prior), ...); * \endcode * * The generality of the approach used here comes at the price of volatility. * There is no builtin error-checking and error-detection on vector sizes. * Specifically, the number of inputs provided by the model must match * the outputs accepted by the likelihood, and the number of dimensions * accepted by the model and prior must be the same. * * \tparam form indicates whether to use the regular or logarithm of the sampling problem; * Gaussian-types of likelihood functions are often used where the regular * form can be \f$ \exp( -0.5 x^2 ) \f$ while the log-form is \f$ -0.5 x^2 \f$, * working with a simple quadratic function can be more stable with respect * to rounding error. * The template parameter \b must be the same as in the call to TasDREAM::SampleDREAM(). * * \param model accepts a set of model inputs and will return the corresponding model values. * - \b candidates is the same as in the input of \b probability_distribution() in * the call to TasDREAM::SampleDREAM(). * Logically the candidates will be arranged in strips of size equal to the problem * dimensions, the vector size will divide evenly by the dimensions and the factor * is the number of candidates. * - \b outputs must be resized to match the number of candidates times the number of outputs, * the behavior must match that of TasmanianSparseGrid::evaluateBatch(). * * \param likelihood accepts a set of model outputs and provides a measure of * how likely those outputs are given some observed data with some noise. * Tasmanian provides likelihood functions that can be used here, e.g., * TasDREAM::LikelihoodGaussIsotropic and TasDREAM::LikelihoodGaussAnisotropic. * - The TasDREAM::TypeSamplingForm will always match the template parameter \b form, * thus, it is sufficient to implement only one sampling from. The Tasmanian likelihood * classes implement both forms, hence the added flexibility. * - The \b model_outputs is a vector with size equal to the number of candidates times * the number of outputs, i.e., must match the output of the \b model. * - The \b likely will have size equal to the number of candidates and must * be filled (without resize) with the likelihood for each set of model outputs. * * \param prior provides the values of the prior distribution in either regular or logarithm form. * The prior will take in the same \b candidates as the model and a vector of the same size as \b likely, * and must return the values of the corresponding prior distribution in either regular or logarithm form. * * Example usage: * \code * auto model = TasGrid::read("foo"); * TasDREAM::LikelihoodGaussIsotropic likely(0.1, data); * TasDREAM::SampleDREAM(..., TasDREAM::posterior(likely, model, TasDREAM::uniform_prior), ...); * \endcode * */ template DreamPDF posterior(DreamModel model, DreamLikelihood likelihood, DreamPrior prior){ return [=](const std::vector &candidates, std::vector &values)->void{ std::vector model_outs; model(candidates, model_outs); likelihood(form, model_outs, values); std::vector prior_vals(values.size()); prior(form, candidates, prior_vals); auto iv = values.begin(); if (form == regform){ for(auto p : prior_vals) *iv++ *= p; }else{ for(auto p : prior_vals) *iv++ += p; } }; } /*! * \ingroup DREAMSampleCore * \brief Overload where the model and likelihood are combined into a single call. * * There are situations where splitting the model and likelihood is undesirable, * e.g., if the model has a huge number of outputs it may be easier to construct * a sparse grid surrogate to the single-output combined model and likelihood. * This is a short hand-template that uses such model-likelihood and combines * it with a prior distribution. */ template DreamPDF posterior(DreamMergedLikelyModel likelihood_model, DreamPrior prior){ return [=](const std::vector &candidates, std::vector &values)->void{ likelihood_model(candidates, values); std::vector prior_vals(values.size()); prior(form, candidates, prior_vals); auto iv = values.begin(); if (form == regform){ for(auto p : prior_vals) *iv++ *= p; }else{ for(auto p : prior_vals) *iv++ += p; } }; } /*! * \brief Core template for the sampling algorithm. * \ingroup DREAMSampleCore * * Evolves the chains of the \b state using the Metropolis algorithm where the updates are comprised of two components, independent and differential. * The independent component relies on independently sampled (pesudo)-random numbers with zero mean (could be deterministic constant zero). * The differential component is based on the difference between two randomly chosen chains, which effectively exchanges information between the chains. * * The implementation is very generic using lambda objects to describe most aspects of the problem, * including the probability distribution, domain, etc. * However, the generality comes with some sacrifice in resilience, i.e., * - each lambda object must respect the problem dimensions, the template will populate the inputs with the correct * number of entries, but the lambdas have to properly utilize the entries. * - each lambda will have to capture external objects and variables and should avoid capture by value for large * vectors, e.g., a sparse grid or a large data vector, while objects captured by reference must remain alive * during the call to the template. * See couple of examples after the variable listing. * * \tparam form indicates whether the \b probability_distribution() function return the regular form or the logarithm of the desired pdf; * in some cases, taking the exponential of a very large negative number can lead to problems with rounding comparison * between numbers very close to zero, hence the logarithm from could be more stable from the round-off error perspective. * * \param num_burnup is the number of initial iterations that will not be saved in the history; * the Metropolis algorithm guarantees convergence to the desired distribution but only in the limit; * when working with a finite number of samples the results can be contaminated by the initial state * which can be significantly different from the limit. * A common practice is to take \b num_burnup to be roughly equal to \b num_collect, but that is only * a heuristic suggestion. * * \param num_collect is the number of iterations that will be saved in the \b state history, * the total number of collected samples is \b num_collect times \b state.getNumChains(). * * \param probability_distribution must accept a vector of \b candidates locations and return the \b values * of the unscaled probability distribution at those points. * The input-output relation is similar to working with TasmanianSparseGrid::evaluateBatch() * when the grid has a a single output. * - The \b candidates input will be logically divided into strips of size \b state.getNumDimensions(), * the total number of strips will be between 1 and \b state.getNumChains() depending * on the number of proposals that fall within the domain, i.e., * the inputs will always satisfy the \b inside() condition. * - The \b values will have size equal to the number of strips and each entry should be filled * the corresponding value of the probability density function. * The \b values vector should not be resized. * - Any TasGrid::TasmanianSparseGrid object with a single output and non-zero loaded points * can be passed in as a \b probability_distribution; when using TasDREAM::regform * the output of the grid must be always non-negative, using TasDREAM::logform has no lower bound requirements. * - In the context of Bayesian inference, there probability distribution is comprised * of three components: model, likelihood, and prior. See TasDREAM::posterior(). * * \param inside must accept a vector of size equal tot he number of dimensions and return \b true * if the vector describes a point in the domain and \b false otherwise. * The function will be called for every proposed sample and unlike the \b probability_distribution * only one vector will be given as input at a time. * Each TasGrid::TasmanianSparseGrid object some with a canonical domain that depends on the rule and * can be optionally transformed, the TasmanianSparseGrid::getDomainInside() method will produce * a lambda object describing the sparse grid domain. * See also TasDREAM::hyperbube(). * * \param state must be an initialized instance of TasmanianDREAM. The number of chains and dimensions must be set * to match the lambda objects and TasmanianDREAM::setState() must be called to load the state with * a valid initial set of vectors. * The \b state will be evolved in total of \b num_burnup + \b num_collect iterations * and the last set of \b num_collect iterations will be appended to the state history. * * \param independent_update must accept a vector of size \b state.getNumDimensions() and (without resizing) * perturb each entry by adding an independent zero-mean random number. * It is possible to omit the \b independent_update, e.g., pass an object that will not modify * the input vector x; however, this can lock the chains to a set of values not dense in the domain * which in turn will break convergence. For example, if the domain is the real line, the initial * state has integer entries, and the \b differential_update is set to 100%, then all proposals * will be integers, non-integer values will never be considered. * TasDREAM::SampleDREAM provides an overload where the independent update is set to * a distribution from an included list with known magnitude. * * \param differential_update is a random or deterministic number between zero and one, * indicating the magnitude of the difference between two randomly chosen chains that will be * added to the next proposal. * Using deterministic zero will decouple the chains, i.e., the state of one chain will * never affect any other chain and the algorithm will reduce to the propagation of * multiple independent chains of the standard Metropolis-Hastings method with * the selected \b independent_update. * Using negative values (by symmetry) is equivalent to using a positive value with the same magnitude, * and values larger than 1 are likely to result in poor mixing and bad convergence rate. * The default differential update is deterministic one and deterministic percentage * can be specified with the \b const_percent() template. * * \param get_random01 is the pseudo-random number generator to be used in the sampling procedure. * By default, Tasmanian will use \b rand() divided by \b RAND_MAX, but this is implementation * dependent and not always optimal. * * Correct call using a sparse grid object as input: * \code * auto grid = TasGrid::read("foo"); // create a grid object * SampleDREAM(..., grid, ...); * // above, the grid will create a lambda object that will capture grid by reference * // the lambda object is destroyed at the end of the call and before grid * \endcode * Incorrect call, \b never \b do \b that: * \code * SampleDREAM(..., TasGrid::read("foo"), ...); // <- Incorrect * // above, read() will create a TasmanianSparseGrid object which will create a lambda * // but the grid will be destroyed before entering the SampleDREAM() and cause a segfault. * \endcode */ template void SampleDREAM(int num_burnup, int num_collect, DreamPDF probability_distribution, DreamDomain inside, TasmanianDREAM &state, std::function &x)> independent_update = no_update, std::function differential_update = const_one, std::function get_random01 = tsgCoreUniform01){ size_t num_chains = (size_t) state.getNumChains(), num_dimensions = (size_t) state.getNumDimensions(); double unitlength = (double) num_chains; if (num_chains == 0) return; // no sampling with a null state if (!state.isStateReady()) throw std::runtime_error("ERROR: DREAM sampling requires that the setState() has been called first on the TasmanianDREAM."); if (!state.isPDFReady()) // initialize probability density (if not initialized already) state.setPDFvalues(probability_distribution); if (num_collect > 0) // pre-allocate memory for the new history state.expandHistory(num_collect); int total_iterations = std::max(num_burnup, 0) + std::max(num_collect, 0); for(int t = 0; t < total_iterations; t++){ std::vector candidates, values; candidates.reserve(num_chains * num_dimensions); values.reserve(num_chains); std::vector valid(num_chains, true); // keep track whether the samples need to be evaluated for(size_t i=0; i propose(num_dimensions); size_t jindex = (size_t) (get_random01() * unitlength); size_t kindex = (size_t) (get_random01() * unitlength); if (jindex >= num_chains) jindex = num_chains - 1; // this is needed in case get_random01() returns 1 if (kindex >= num_chains) jindex = num_chains - 1; state.getIJKdelta(i, jindex, kindex, differential_update(), propose); // propose = s_i + w ( s_k - s_j) independent_update(propose); // propose += correction if (inside(propose)){ candidates.insert(candidates.end(), propose.begin(), propose.end()); values.resize(values.size() + 1); }else{ valid[i] = false; } } if (!candidates.empty()) // block the pathological case of all proposals leaving the domain probability_distribution(candidates, values); std::vector new_state(num_chains * num_dimensions), new_values(num_chains); auto icand = candidates.begin(); // loop over all candidates and values, accept or reject auto ival = values.begin(); size_t accepted = 0; for(size_t i=0; i state.getPDFvalue(i)){ // if the new value has higher probability, automatically accept keep_new = true; }else{ if (form == regform){ keep_new = (*ival / state.getPDFvalue(i) >= get_random01()); // keep if the new value has higher probability }else{ keep_new = (*ival - state.getPDFvalue(i) >= log(get_random01())); } //std::cout << "Trsh = " << *ival / state.getPDFvalue(i) << " " << ((keep_new) ? "Accept" : "Reject") << std:: endl; } } if (keep_new){ std::copy_n(icand, num_dimensions, new_state.begin() + i * num_dimensions); new_values[i] = *ival; accepted++; // accepted one more proposal }else{ // reject and reuse the old state state.getChainState((int) i, &*(new_state.begin() + i * num_dimensions)); new_values[i] = state.getPDFvalue(i); } if (valid[i]){ // kept or rejected, if this sample was valid then move to the next sample in the list std::advance(icand, num_dimensions); ival++; } } state.setState(new_state); state.setPDFvalues(new_values); if (t >= num_burnup) state.saveStateHistory(accepted); } } /*! * \ingroup DREAMSampleCore * \brief Overload of \b SampleDREAM() assuming independent update from a list of internally implemented options. * * Uses independent update is applied uniformly to all dimensions * and comes from a list of internal functions, e.g., uniform or Gaussian. * This overload wraps around functions such as * \b TasDREAM::applyUniformCorrection() and \b TasDREAM::applyGaussianCorrection(). */ template void SampleDREAM(int num_burnup, int num_collect, DreamPDF probability_distribution, DreamDomain inside, TasmanianDREAM &state, TypeDistribution dist, double magnitude, std::function differential_update = const_one, std::function get_random01 = tsgCoreUniform01){ if (dist == dist_uniform){ SampleDREAM
(num_burnup, num_collect, probability_distribution, inside, state, [&](std::vector &x)->void{ applyUniformUpdate(x, magnitude, get_random01); }, differential_update, get_random01); }else if (dist == dist_gaussian){ SampleDREAM(num_burnup, num_collect, probability_distribution, inside, state, [&](std::vector &x)->void{ applyGaussianUpdate(x, magnitude, get_random01); }, differential_update, get_random01); }else{ // assuming none SampleDREAM(num_burnup, num_collect, probability_distribution, inside, state, no_update, differential_update, get_random01); } } } #endif TASMANIAN-8.1/DREAM/tsgDreamSampleWrapC.cpp000066400000000000000000000260661470551176200201200ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_SAMPLE_WRAPC_CPP #define __TASMANIAN_DREAM_SAMPLE_WRAPC_CPP #include "tsgDreamSample.hpp" namespace TasDREAM{ using tsg_dream_pdf = void (*)(int, int, const double[], double[], int*); using tsg_dream_domain = int (*)(int, const double[]); using tsg_dream_iupdate = void (*)(int, double[], int*); using tsg_dream_dupdate = double (*)(); using tsg_dream_random = double (*)(); std::function &x)> getSpecifiedDomain(int num_dimensions, void *domain_grid, double *domain_lower, double *domain_upper, tsg_dream_domain domain_callback){ if (domain_grid != nullptr){ return reinterpret_cast(domain_grid)->getDomainInside(); }else if (domain_upper != nullptr){ return hypercube(std::vector(domain_lower, domain_lower + num_dimensions), std::vector(domain_upper, domain_upper + num_dimensions)); }else{ return [=](std::vector const &x)-> bool{ return (domain_callback((int) x.size(), x.data()) != 0); }; } } std::function getSpecifiedDifferentialUpdate(int dupdate_percent, tsg_dream_dupdate dupdate_callback){ if (dupdate_percent >= 0){ return [=]()->double{ return double(dupdate_percent) / 100.0; }; }else{ return [=]()->double{ return dupdate_callback(); }; } } extern "C"{ void tsgGenUniformSamples(int num_dimensions, int num_samples, double const lower[], double const upper[], const char* random_type, int random_seed, tsg_dream_random random_callback, double *samples){ std::minstd_rand park_miller((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed); std::uniform_real_distribution unif(0.0, 1.0); srand((unsigned int) ((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed)); std::string rtype(random_type); auto randgen = [&]()-> std::function{ if (rtype == "default"){ return [&]()->double{ return tsgCoreUniform01(); }; }else if (rtype == "minstd_rand"){ return [&]()->double{ return unif(park_miller); }; }else{ return [&]()->double{ return random_callback(); }; } }(); std::vector result = TasDREAM::genUniformSamples(Utils::copyArray(lower, num_dimensions), Utils::copyArray(upper, num_dimensions), num_samples, randgen); std::copy(result.begin(), result.end(), samples); } void tsgGenGaussianSamples(int num_dimensions, int num_samples, double const mean[], double const deviation[], const char* random_type, int random_seed, tsg_dream_random random_callback, double *samples){ std::minstd_rand park_miller((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed); std::uniform_real_distribution unif(0.0, 1.0); srand((unsigned int) ((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed)); std::string rtype(random_type); auto randgen = [&]()-> std::function{ if (rtype == "default"){ return [&]()->double{ return tsgCoreUniform01(); }; }else if (rtype == "minstd_rand"){ return [&]()->double{ return unif(park_miller); }; }else{ return [&]()->double{ return random_callback(); }; } }(); std::vector result = TasDREAM::genGaussianSamples(Utils::copyArray(mean, num_dimensions), Utils::copyArray(deviation, num_dimensions), num_samples, randgen); std::copy(result.begin(), result.end(), samples); } void tsgDreamSample(int form, int num_burnup, int num_collect, tsg_dream_pdf distribution, void* state_pntr, void *domain_grid, double domain_lower[], double dommain_upper[], tsg_dream_domain domain_callback, const char* iupdate_type, double iupdate_magnitude, tsg_dream_iupdate iupdate_callback, int dupdate_percent, tsg_dream_dupdate dupdate_callback, const char* random_type, int random_seed, tsg_dream_random random_callback, int *err){ *err = 1; TasmanianDREAM& state = *reinterpret_cast(state_pntr); int num_dimensions = (int) state.getNumDimensions(); auto domain = getSpecifiedDomain(num_dimensions, domain_grid, domain_lower, dommain_upper, domain_callback); TypeDistribution dist = IO::getDistributionString(iupdate_type); auto diff_update = getSpecifiedDifferentialUpdate(dupdate_percent, dupdate_callback); std::minstd_rand park_miller((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed); std::uniform_real_distribution unif(0.0, 1.0); srand((unsigned int) ((random_seed == -1) ? static_cast(std::time(nullptr)) : random_seed)); std::string rtype(random_type); auto randgen = [&]()-> std::function{ if (rtype == "default"){ return [&]()->double{ return tsgCoreUniform01(); }; }else if (rtype == "minstd_rand"){ return [&]()->double{ return unif(park_miller); }; }else{ return [&]()->double{ return random_callback(); }; } }(); try{ if (dist == dist_null){ if (IO::intToForm(form) == regform){ SampleDREAM(num_burnup, num_collect, [&](const std::vector &candidates, std::vector &values)-> void{ int num_samples = (int) candidates.size() / num_dimensions; int error_code = 0; distribution(num_samples, num_dimensions, candidates.data(), values.data(), &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgDreamSample()"); }, domain, state, [&](std::vector &x)-> void{ int error_code = 0; iupdate_callback((int) x.size(), x.data(), &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgDreamSample()"); }, diff_update, randgen); }else{ SampleDREAM(num_burnup, num_collect, [&](const std::vector &candidates, std::vector &values)-> void{ int num_samples = (int) candidates.size() / num_dimensions; int error_code = 0; distribution(num_samples, num_dimensions, candidates.data(), values.data(), &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgDreamSample()"); }, domain, state, [&](std::vector &x)-> void{ int error_code = 0; iupdate_callback((int) x.size(), x.data(), &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgDreamSample()"); }, diff_update, randgen); } }else{ if (IO::intToForm(form) == regform){ SampleDREAM(num_burnup, num_collect, [&](const std::vector &candidates, std::vector &values)-> void{ int num_samples = (int) candidates.size() / num_dimensions; int error_code = 0; distribution(num_samples, num_dimensions, candidates.data(), values.data(), &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in tsgDreamSample()"); }, domain, state, dist, iupdate_magnitude, diff_update, randgen); }else{ SampleDREAM(num_burnup, num_collect, [&](const std::vector &candidates, std::vector &values)-> void{ int num_samples = (int) candidates.size() / num_dimensions; int error_code = 0; distribution(num_samples, num_dimensions, candidates.data(), values.data(), &error_code); if (error_code != 0) throw std::runtime_error("The Python callback returned an error in analysis()"); }, domain, state, dist, iupdate_magnitude, diff_update, randgen); } } *err = 0; // success }catch(std::runtime_error &){} // *err will remain 1 } } } #endif TASMANIAN-8.1/DREAM/tsgDreamState.cpp000066400000000000000000000210561470551176200170140ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_STATE_CPP #define __TASMANIAN_DREAM_STATE_CPP #include "tsgDreamState.hpp" namespace TasDREAM{ TasmanianDREAM::TasmanianDREAM() : num_chains(0), num_dimensions(0), init_state(false), init_values(false), accepted(0){} TasmanianDREAM::TasmanianDREAM(int cnum_chains, int cnum_dimensions) : num_chains(cnum_chains), num_dimensions(cnum_dimensions), init_state(false), init_values(false), accepted(0){ if (cnum_chains < 1) throw std::invalid_argument("ERROR: num_chains must be positive"); if (cnum_dimensions < 1) throw std::invalid_argument("ERROR: num_dimensions must be positive"); } TasmanianDREAM::TasmanianDREAM(int cnum_chains, const TasGrid::TasmanianSparseGrid &grid) : num_chains(cnum_chains), num_dimensions(grid.getNumDimensions()), init_state(false), init_values(false), accepted(0){ if (cnum_chains < 1) throw std::invalid_argument("ERROR: num_chains must be positive"); if (grid.getNumDimensions() < 1) throw std::invalid_argument("ERROR: num_dimensions must be positive"); } TasmanianDREAM::~TasmanianDREAM(){} void TasmanianDREAM::setState(const std::vector &new_state){ if (new_state.size() != num_chains * num_dimensions) throw std::runtime_error("ERROR: new state has incorrect dimension, must be num_chains times num_dimensions."); state = new_state; init_state = true; init_values = false; } void TasmanianDREAM::setState(std::function update_state){ state.resize(num_chains * num_dimensions); auto istate = state.begin(); for(size_t i=0; i &new_values){ if (new_values.size() != num_chains) throw std::runtime_error("ERROR: new_values has incorrect dimension, must match num_chains."); pdf_values = new_values; init_values = true; } void TasmanianDREAM::setPDFvalues(std::function &state, std::vector &values)> probability_distribution){ if (!init_state) throw std::runtime_error("ERROR: calling setPDFvalues() with a function requires that the state is set first."); pdf_values.resize(num_chains); probability_distribution(state, pdf_values); init_values = true; } void TasmanianDREAM::clearPDFvalues(){ pdf_values = std::vector(); init_values = false; } void TasmanianDREAM::getIJKdelta(size_t i, size_t j, size_t k, double w, std::vector &x) const{ std::copy_n(state.begin() + i * num_dimensions, num_dimensions, x.data()); if (w != 0.0){ auto ik = state.begin() + k * num_dimensions; auto ij = state.begin() + j * num_dimensions; for(auto &xv : x) xv += w * (*ik++ - *ij++); } } void TasmanianDREAM::expandHistory(int num_snapshots){ history.reserve(history.size() + num_snapshots * num_dimensions * num_chains); pdf_history.reserve(pdf_history.size() + num_snapshots * num_chains); } void TasmanianDREAM::saveStateHistory(size_t num_accepted){ history.insert(history.end(), state.begin(), state.end()); pdf_history.insert(pdf_history.end(), pdf_values.begin(), pdf_values.end()); accepted += num_accepted; } void TasmanianDREAM::getHistoryMeanVariance(std::vector &mean, std::vector &var) const{ mean.resize(num_dimensions); var.resize(num_dimensions); std::fill(mean.begin(), mean.end(), 0.0); std::fill(var.begin(), var.end(), 0.0); if (num_dimensions == 0) return; auto ih = history.begin(); while(ih != history.end()){ auto im = mean.begin(); auto iv = var.begin(); for(size_t i=0; i &mode) const{ auto imax = std::max_element(pdf_history.begin(), pdf_history.end()); mode.resize(num_dimensions); std::copy_n(history.begin() + std::distance(pdf_history.begin(), imax) * num_dimensions, num_dimensions, mode.data()); } void TasmanianDREAM::clearHistory(){ history = std::vector(); pdf_history = std::vector(); accepted = 0; } extern "C"{ // for python purposes void* tsgMakeDreamState(int num_chains, int num_dimensions){ return (void*) new TasmanianDREAM(num_chains, num_dimensions); } void tsgDeleteDreamState(void* state){ delete reinterpret_cast(state); } int tsgDreamStateGetDims(void *state){ return reinterpret_cast(state)->getNumDimensions(); } int tsgDreamStateGetChains(void *state){ return reinterpret_cast(state)->getNumChains(); } int tsgDreamStateGetNumHistory(void *state){ return (int) reinterpret_cast(state)->getNumHistory(); } void tsgDreamStateSet(void *state, double const x[]){ std::vector vx(x, x + Utils::size_mult(reinterpret_cast(state)->getNumChains(), reinterpret_cast(state)->getNumDimensions())); reinterpret_cast(state)->setState(vx); } void tsgDreamStateGetHistory(void *state, double hist[]){ auto h = reinterpret_cast(state)->getHistory(); std::copy(h.begin(), h.end(), hist); } void tsgDreamStateGetHistoryPDF(void *state, double histpdf[]){ auto h = reinterpret_cast(state)->getHistoryPDF(); std::copy(h.begin(), h.end(), histpdf); } void tsgDreamStateGetMeanVar(void *state, double mean[], double variance[]){ std::vector mn, var; reinterpret_cast(state)->getHistoryMeanVariance(mn, var); std::copy(mn.begin(), mn.end(), mean); std::copy(var.begin(), var.end(), variance); } void tsgDreamStateGetMode(void *state, double mode[]){ auto m = reinterpret_cast(state)->getApproximateMode(); std::copy(m.begin(), m.end(), mode); } double tsgDreamStateGetRate(void *state){ return reinterpret_cast(state)->getAcceptanceRate(); } } } #endif TASMANIAN-8.1/DREAM/tsgDreamState.hpp000066400000000000000000000244651470551176200170300ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DREAM_STATE_HPP #define __TASMANIAN_DREAM_STATE_HPP #include "tsgDreamEnumerates.hpp" //! \internal //! \file tsgDreamState.hpp //! \brief The container class holding the DREAM history. //! \author Miroslav Stoyanov //! \ingroup TasmanianDREAM //! //! Defines the TasmanianDREAM class which stores the history of the MCMC samples. /*! * \ingroup TasmanianDREAM * \addtogroup DREAMState TasmanianDREAM State * * Keeps the current state of the DREAM chains and stores the history * of a MCMC sampling. */ namespace TasDREAM{ //! \brief Contains the current state and the history of the DREAM chains. //! \ingroup DREAMState //! \par DREAM State //! The DREAM state consists of \b num_chains vectors of size \b num_dimensions, //! where the dimension is either specified or inferred from the given sparse grid. //! Each vector is also associated with a //! value of the corresponding probability density function (pdf). //! The history of the state consists of multiple snapshots of the vectors and //! the pdf values. //! //! \par Container class //! The TasmanianDREAM class is a container for the current state and history, //! where the vectors are stored using std::vector data structures. //! Methods are provided for file I/O, direct access to the data and //! several handy queries for inference or optimization problems. class TasmanianDREAM{ public: //! \brief Constructor for a null DREAM state, no chains and no dimensions (used for MPI purposes). TasmanianDREAM(); //! \brief Constructor for a DREAM state with the number of chains and dimensions. TasmanianDREAM(int cnum_chains, int cnum_dimensions); //! \brief Constructor for a DREAM state with the number of chains and the dimension of the sparse grid. TasmanianDREAM(int cnum_chains, const TasGrid::TasmanianSparseGrid &grid); //! \brief Default destructor, release all used memory. ~TasmanianDREAM(); //! \brief Return human readable string with the version. static const char* getVersion(){ return TASMANIAN_VERSION_STRING; } //! \brief Return human readable sting with the license, refer to the LICENSE file for details. static const char* getLicense(){ return TASMANIAN_LICENSE; } //! \brief Return the major version of the library. static int getVersionMajor(){ return TASMANIAN_VERSION_MAJOR; } //! \brief Return the minor version of the library. static int getVersionMinor(){ return TASMANIAN_VERSION_MINOR; } //! \brief Return the number of dimensions. int getNumDimensions() const{ return (int) num_dimensions; } //! \brief Return the number of chains. int getNumChains() const{ return (int) num_chains; } //! \brief Return the number of saved vectors in the history. size_t getNumHistory() const{ return pdf_history.size(); } //! \brief Return \b true if the state has already been initialized with \b setState(). bool isStateReady() const{ return init_state; } //! \brief Return \b true if the pdf values have already been initialized with \b setPDF(). bool isPDFReady() const{ return init_values; } //! \brief Set the current DREAM state to the \b new_state. //! The \b new_state must have size equal to num_chains times num_dimensions, the first //! chain should be stored in the first num_dimensions entries, the second chain in the //! second batch of num_dimensions entries, and so on. void setState(const std::vector &new_state); //! \brief Set the current DREAM state by calling \b update_state on each vector. //! The \b update_state function will be given each state vector as an array and //! the function should overwrite the entries with the desired current state. //! For example, \b update_state can overwrite the array with random numbers sampled //! according to a desired probability distribution. void setState(std::function update_state); //! \brief Set the current set of pdf values to the \b new_values. //! The \b new_values must have size equal to the number of chains, //! the current set of pdf values are overwritten with the new ones. //! Note: that there is no restriction on the sign of the values, //! since log-form sampling can result in negative values. void setPDFvalues(const std::vector &new_values); //! \brief Set the current set of pdf values using the given \b probability_distribution. //! Calls the \b probability_distribution function wit the current state (the state must be already initialized). //! The \b probability_distribution is the same function as in the \b DREAM sampling call, //! in order to avoid discrepancy, it may be best to leave the PDF values uninitialized and //! let the \b DREAM sampler to call \b setPDFvalues() automatically. void setPDFvalues(std::function &state, std::vector &values)> probability_distribution); //! \brief Erase the currently stored pdf values, useful when switching between log and non-log form sampling. void clearPDFvalues(); //! \brief Used by the \b DREAM sampler, \f$ x = s_i + w ( s_k - s_j) \f$, where \b s indicates the current i, j, and k-th state vectors. //! Used by the \b DREAM sampler and probably should not be called by the user. //! This returns the vector of the \b i-th chain corrected by the difference //! between the \b k-th and \b j-th chain and weighted by \b w. //! The result is written to the array \b x, which must have size at least num_dimensions. void getIJKdelta(size_t i, size_t j, size_t k, double w, std::vector &x) const; //! \brief Return the state of the \b i-th chain, store an array \b x of size at least num_dimensions. //! Used by the \b DREAM sampler and probably should not be called by the user. void getChainState(size_t i, double *x) const{ std::copy_n(state.begin() + i * num_dimensions, num_dimensions, x); } //! \brief Return a const reference to the internal state vector. const std::vector& getChainState() const{ return state; } //! \brief Return the value of the probability_distribution of the \b i-th chain. //! Used by the \b DREAM sampler and probably should not be called by the user. double getPDFvalue(size_t i) const{ return pdf_values[i]; } //! \brief Allocate (expand) internal storage for the history snapshots, avoids reallocating data when saving a snapshot. //! Used by the \b DREAM sampler and probably should not be called by the user. void expandHistory(int num_snapshots); //! \brief Appends the current state to the history. //! Used by the \b DREAM sampler and probably should not be called by the user; \b num_accepted is the number of new chains in the state. void saveStateHistory(size_t num_accepted); //! \brief Return a const reference to the internal state vector. const std::vector& getHistory() const{ return history; } //! \brief Return a const reference to the internal state vector. const std::vector& getHistoryPDF() const{ return pdf_history; } //! \brief Compute the means and variance of the saved history. void getHistoryMeanVariance(std::vector &mean, std::vector &var) const; //! \brief Return the sample with highest probability, searchers within the history. void getApproximateMode(std::vector &mode) const; //! \brief Overload that returns the vector. std::vector getApproximateMode() const{ std::vector mode; getApproximateMode(mode); return mode; } //! \brief Clear the stored history (does not touch the state). void clearHistory(); //! \brief Returns the acceptance rate of the current history. double getAcceptanceRate() const{ return ((pdf_history.empty()) ? 0 : ((double) accepted) / ((double) pdf_history.size())); } // file I/O private: size_t num_chains, num_dimensions; bool init_state, init_values; size_t accepted; std::vector state, history; std::vector pdf_values, pdf_history; }; } #endif TASMANIAN-8.1/Doxygen/000077500000000000000000000000001470551176200143225ustar00rootroot00000000000000TASMANIAN-8.1/Doxygen/CMakeLists.txt000066400000000000000000000211511470551176200170620ustar00rootroot00000000000000find_package(Doxygen REQUIRED OPTIONAL_COMPONENTS dot) set(DOXYGEN_GENERATE_HTML "YES") set(DOXYGEN_DISABLE_INDEX "NO") set(DOXYGEN_GENERATE_TREEVIEW "YES") # left-hand index set(DOXYGEN_SORT_GROUP_NAMES "NO") # disable automatic sorting set(DOXYGEN_SORT_MEMBER_DOCS "NO") # use the order in the source files (logical order) set(DOXYGEN_SORT_BRIEF_DOCS "NO") # which is more logical than the alphabetical one # skip sections marked with __TASMANIAN_DOXYGEN_SKIP to avoid extraneous warnings # document all options regardless of the build, mostly affects the internal API set(DOXYGEN_PREDEFINED "__TASMANIAN_DOXYGEN_SKIP;Tasmanian_ENABLE_BLAS;Tasmanian_ENABLE_CUDA;Tasmanian_ENABLE_MPI") set(DOXYGEN_HTML_EXTRA_STYLESHEET ${CMAKE_CURRENT_SOURCE_DIR}/tasmanian.css) set(DOXYGEN_HTML_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/header.html") set(DOXYGEN_HTML_FOOTER "${CMAKE_CURRENT_SOURCE_DIR}/footer.html") set(DOXYGEN_HTML_COLORSTYLE_HUE "175") # green-ish pages set(DOXYGEN_HTML_COLORSTYLE_SAT "50") set(DOXYGEN_HTML_COLORSTYLE_GAMMA "90") set(DOXYGEN_FORMULA_FONTSIZE "14") set(DOXYGEN_USE_MATHJAX "NO") set(DOXYGEN_PROJECT_NAME "Toolkit for Adaptive Stochastic Modeling and Non-Intrusive ApproximatioN: ${PROJECT_NAME} v${Tasmanian_VERSION_MAJOR}.${Tasmanian_VERSION_MINOR}${Tasmanian_version_comment}") set(DOXYGEN_PROJECT_NUMBER "") # if project number is given, the rendered font is too small set(DOXYGEN_EXAMPLE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../") # finding the examples for all modules requires the use of the root dir if (NOT DOXYGEN_INTERNAL_DOCS) # the \internal command works for functions and namespaces, but not classes # have to exclude the classes manually set(DOXYGEN_EXCLUDE_SYMBOLS TasGrid::Data2D TasGrid::MultiIndexSet TasGrid::StorageSet TasGrid::CustomTabulated TasGrid::OneDimensionalWrapper TasGrid::TasSparse::WaveletBasisMatrix TasGrid::GpuEngine TasGrid::GpuVector TasGrid::AccelerationDomainTransform TasGrid::AccelerationContext TasGrid::TableGaussPatterson TasGrid::InternalSyclQueue TasBLAS TasGrid::TasmanianDenseSolver TasGrid::TasmanianTridiagonalSolver TasGrid::Utils TasGrid::NodeData TasGrid::TensorData TasGrid::CacheLagrange TasGrid::CacheLagrangeDerivative TasGrid::MultiIndexManipulations::ProperWeights TasGrid::HierarchyManipulations::SplitDirections TasGrid::Utils::Wrapper2D TasGrid::SimpleConstructData TasGrid::DynamicConstructorDataGlobal TasGrid::Optimizer::CurrentNodes TasGrid::Optimizer::HasDerivative TasGrid::Optimizer::OptimizerResult TasGrid::VectorToStreamBuffer TasGrid::CandidateManager TasGrid::CompleteStorage TasGrid::IO::mode_ascii_type TasGrid::IO::mode_binary_type TasGrid::HandleDeleter TasGrid::AccHandle::Cublas TasGrid::AccHandle::Cusparse TasGrid::AccHandle::Cusolver TasGrid::AccHandle::Rocblas TasGrid::AccHandle::Rocsparse TasGrid::AccHandle::Syclqueue TasGrid::tsg_gpu_selector TasGrid::int_gpu_lapack TasDREAM::IO TasDREAM::Utils) set(DOXYGEN_PREDEFINED "__TASMANIAN_DOXYGEN_SKIP;__TASMANIAN_DOXYGEN_SKIP_INTERNAL;Tasmanian_ENABLE_BLAS;Tasmanian_ENABLE_CUDA;Tasmanian_ENABLE_DPCPP;Tasmanian_ENABLE_HIP;Tasmanian_ENABLE_MPI") endif() ### Add the git-hash to the main page, suppress at release (the stable page needs no hash) file(READ "${CMAKE_CURRENT_SOURCE_DIR}/../README.md" Tasmanian_readme) string(REPLACE "# Tasmanian" "# Tasmanian\n * *Generated from git commit ${Tasmanian_git_hash}*" Tasmanian_readme ${Tasmanian_readme}) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/README.md" "${Tasmanian_readme}") set(DOXYGEN_USE_MDFILE_AS_MAINPAGE "${CMAKE_CURRENT_BINARY_DIR}/README.md") doxygen_add_docs(Tasmanian_doxygen ${CMAKE_CURRENT_BINARY_DIR}/README.md Doxygen/Contributors.md Doxygen/Installation.md Doxygen/InterfacePython.md Doxygen/InterfaceLibEnsemble.md Doxygen/InterfaceCLI.md Doxygen/InterfaceMATLAB.md Doxygen/InterfaceFortran2003.md Doxygen/CustomRuleFileFormat.md Config/Tasmanian.hpp SparseGrids/TasmanianSparseGrid.hpp DREAM/TasmanianDREAM.hpp DREAM/Optimization/TasmanianOptimization.hpp Addons/TasmanianAddons.hpp SparseGrids/tsgEnumerates.hpp SparseGrids/tsgUtils.hpp SparseGrids/tsgMathUtils.hpp SparseGrids/tsgIndexSets.hpp SparseGrids/tsgIndexManipulator.hpp SparseGrids/tsgIndexManipulator.cpp SparseGrids/tsgHierarchyManipulator.hpp SparseGrids/tsgIOHelpers.hpp SparseGrids/tsgAcceleratedHandles.hpp SparseGrids/tsgAcceleratedDataStructures.hpp SparseGrids/tsgCudaLoadStructures.hpp SparseGrids/tsgCacheLagrange.hpp SparseGrids/tsgCoreOneDimensional.hpp SparseGrids/tsgOneDimensionalWrapper.hpp SparseGrids/tsgHardCodedTabulatedRules.hpp SparseGrids/tsgLinearSolvers.hpp SparseGrids/tsgDConstructGridGlobal.hpp SparseGrids/tsgSequenceOptimizer.hpp SparseGrids/tsgSequenceOptimizer.cpp SparseGrids/tsgRuleWavelet.hpp SparseGrids/tsgRuleLocalPolynomial.hpp SparseGrids/tsgGridCore.hpp SparseGrids/tsgGridGlobal.hpp SparseGrids/tsgGridSequence.hpp SparseGrids/tsgGridLocalPolynomial.hpp SparseGrids/tsgGridWavelet.hpp SparseGrids/tsgGridFourier.hpp DREAM/tsgDreamState.hpp DREAM/tsgDreamSample.hpp DREAM/tsgDreamEnumerates.hpp DREAM/tsgDreamCoreRandom.hpp DREAM/tsgDreamCorePDF.hpp DREAM/tsgDreamLikelihoodCore.hpp DREAM/tsgDreamLikelyGaussian.hpp DREAM/Optimization/tsgParticleSwarm.hpp DREAM/Optimization/tsgGradientDescent.hpp DREAM/Optimization/tsgOptimizationUtils.hpp Addons/tsgExoticQuadrature.hpp Addons/tsgConstructSurrogate.hpp Addons/tsgCandidateManager.hpp Addons/tsgLoadUnstructuredPoints.hpp Addons/tsgMPIConstructGrid.hpp Addons/tsgMPISampleDream.hpp Addons/tsgMPIScatterDream.hpp Addons/tsgMPIScatterGrid.hpp Addons/tsgLoadNeededValues.hpp Addons/tsgAddonsCommon.hpp InterfaceTPL/tsgTPLWrappers.hpp InterfaceTPL/tsgBlasWrappers.hpp InterfaceTPL/tsgGpuWrappers.hpp SparseGrids/Examples/example_sparse_grids.cpp SparseGrids/Examples/example_sparse_grids_01.cpp SparseGrids/Examples/example_sparse_grids_02.cpp SparseGrids/Examples/example_sparse_grids_03.cpp SparseGrids/Examples/example_sparse_grids_04.cpp SparseGrids/Examples/example_sparse_grids_05.cpp SparseGrids/Examples/example_sparse_grids_06.cpp SparseGrids/Examples/example_sparse_grids_07.cpp SparseGrids/Examples/example_sparse_grids_08.cpp SparseGrids/Examples/example_sparse_grids_09.cpp SparseGrids/Examples/example_sparse_grids_10.cpp SparseGrids/Examples/example_sparse_grids_11.cpp DREAM/Examples/example_dream.cpp DREAM/Examples/example_dream_01.cpp DREAM/Examples/example_dream_02.cpp DREAM/Examples/example_dream_03.cpp DREAM/Examples/example_dream_04.cpp DREAM/Examples/example_dream_05.cpp DREAM/Examples/example_optimization.cpp DREAM/Examples/example_optimization_01.cpp DREAM/Examples/example_optimization_02.cpp WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../ COMMENT "Tasmanian Doxygen documentation") # doxygen_add_docs() doesn't add the target to "all" # need to manually add dependence to ensure the docs are build before "install" # adding Tasmanian_doxygen to both sparse grids libraries forces the docs to be build first # even if parallel build is used (e.g., make -j) this will keep the c++ and doxygen outputs separate add_dependencies(Tasmanian_libsparsegrid Tasmanian_doxygen) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION "share/Tasmanian/docs") TASMANIAN-8.1/Doxygen/Contributors.md000066400000000000000000000022611470551176200173420ustar00rootroot00000000000000# Development Team ### Current Contributors **Miroslav Stoyanov**
Lead Developer
Oak Ridge National Lab **Damien T. Lebrun-Grandie**
Conforming to standards and CI testing
Oak Ridge National Lab **Paul Laiu**
Fortran and application integration
Oak Ridge National Lab **Viktor Reshniak**
Fortran integration and build systems
Oak Ridge National Lab **Guannan Zhang**
Core DREAM capabilities
Oak Ridge National Lab ### Former Contributors **William Kong**
Developer
Exotic quadrature, optimization modules, libEnsemble integration,
many miscellaneous contributions
Oak Ridge National Lab **Zack Morrow**
Core Fourier capabilities
North Carolina State University **Nicholas Dexter**
Contributor to core functionality and API
University of Tennessee at Knoxville **Clayton Webster**
Principal Investigator
Oak Ridge National Lab **John Burkardt**
Core functionality
Florida State University **Diego Galindo**
Contributor to core functionality and API
Oak Ridge National Lab **Drayton Munster**
Core Wavelet capabilities
Virginia Tech TASMANIAN-8.1/Doxygen/CustomRuleFileFormat.md000066400000000000000000000100221470551176200207120ustar00rootroot00000000000000# Custom Rule File Format The custom rule functionality allows the creation of a sparse grid using a rule other than the ones implemented in the code. The custom rule is defined via a file with tables that list the levels, number of points per level, exactness of the quadrature at each level, points and their associated weights. Currently, the custom rules work only with global grids and hence the interpolant associated with the rule is a global interpolant using Lagrange polynomials. The custom rule is defined via custom rule file, with the following format: * **line 1:** should begin with the string **description:** and it should be followed by a string with a short description of the rule. This string is used only for human readability purposes. * **line 2:** should begin with the string **levels:** followed by an integer indicating the total number of rule levels defined in the file. After the description and total number of levels have been defined, the file should contain a sequence of integers describing the number of points and exactness, followed by a sequence of floating point numbers listing the points and weights. * **integers:** is a sequence of integer pairs where the first integer indicates the number of points for the current level and the second integer indicates the exactness of the rule. For example, the first 3 levels of the Gauss-Legendre rule will be described via the sequence (1, 1 , 2 , 3 , 3 , 5), while the first 3 levels of the Clenshaw-Curtis rule will be described via (1 , 1 , 3 , 3 , 5 , 5). * **floats:** is a sequence of floating point pairs describing the weights and points. The first number of the pair is the quadrature weight, while the second number if the abscissa. The points associated with the first level are listed in the first pairs. The second set of pairs lists the points associated with the second level and so on. Here is an example of Gauss-Legendre 3 level rule for reference purposes: ``` description: Gauss-Legendre rule levels: 3 1 1 2 3 3 5 2.0 0.0 1.0 -0.5774 1.0 0.5774 0.5556 -0.7746 0.8889 0.0 0.5556 0.7746 ``` Similarly, a level 3 Clenshaw-Curtis rule can be defined as ``` description: Clenshaw-Curtis rule levels: 3 1 1 3 3 5 5 2.0 0.0 0.333 1.0 1.333 0.0 0.333 -1.0 0.8 0.0 0.067 -1.0 0.067 1.0 0.533 -0.707 0.533 0.707 ``` Several notes on the custom rule file format: * Tasmanian works with double precision and hence a custom rule should be defined with the corresponding number of significant digits. The examples above are for illustrative purposes only. * The order of points within each level is irrelevant. Tasmanian will internally index the points. * Points that are within distance of *1.E-12* of each other will be treated as the same point. Thus, repeated (nested) points can be automatically handled by the code. The tolerance can be adjusted in **tsgMathUtils.hpp** by modifying the **num_tol** constant, * Naturally, Tasmanian cannot create a sparse grid that requires a one dimensional rule with level higher than what is provided in the file. Predicting the required number of levels can be hard in the case of anisotropic grids, the code will raise a `std::runtime_error` if the custom rule does not provide a sufficient number of points. * The exactness constants are used only if **qptotal** or **qpcurved** types are used and the indexes of the polynomial space, i.e., **getPolynomialIndexes()**. If quadrature rules are not used, then the exactness integers can be set to 0. * The quadrature weights are used only if integration is performed. If no quadrature or integration is used, then the weights can all be set to 0. * If a custom rule is used together with **setDomainTransform()**, then the transform will assume that the rule is defined on the canonical interval `[-1,1]`. A custom rule can be defined on any arbitrary interval, however, for any interval different from `[-1,1]` the **setDomainTransform()** functions should not be used. * Tasmanian comes with an example custom rule file that defines 9 levels of the Gauss-Legendre-Patterson rule, a.k.a., nested Gauss-Legendre rule. TASMANIAN-8.1/Doxygen/DevNotes.md000066400000000000000000000010551470551176200163740ustar00rootroot00000000000000# Developer Notes Notes and checklists for Tasmanian developers to help procedures such as release checklists and version bumps. #### Version Bump When increasing the version, e.g., 7.5 to 7.6: * update the project directive project() in the main CMakeLists.txt file * set the `Tasmanian_version_comment` variable to develop, release candidate, or release (empty) * update the Makefile * update `Config/AltBuildSystems/TasmanianConfig.hpp` * update the `setup.py` in `InterfacePython\PipInstaller` #### Release Checklist When making a new release: TODOTASMANIAN-8.1/Doxygen/Installation.md000066400000000000000000000524711470551176200173160ustar00rootroot00000000000000# Installation [TOC] ### Document Sections * Requirements * Install using CMake: the preferred way * Install with (basic) GNU Make * Install with Python Pip * Install with Spack * Install on MS Windows platform * Install folder structure * Linking to Tasmanian: CMake Package Config * Known issues ### Requirements Minimum requirements to use Tasmanian: * a C/C++ compiler and either [CMake](https://cmake.org/) or [GNU Make](https://www.gnu.org/software/make/) build engines. Recommended additional features: * [Python](https://www.python.org/) with with [NumPy](http://www.numpy.org/) 1.10 (or newer) and [CTypes](https://docs.python.org/3/library/ctypes.html) packages * [Basic Linear Algebra Subroutine (BLAS)](https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms) implementation * [Linear Algebra PACKage](http://www.netlib.org/lapack/) implementation * [OpenMP](https://en.wikipedia.org/wiki/OpenMP) implementation (usually included with the compiler) Optional features: * Acceleration using [OpenMP](https://www.openmp.org/) multicore algorithms (CPU only), the OpenMP standard is supported on most major compilers. * Acceleration using Nvidia [linear algebra libraries](https://developer.nvidia.com/cublas) and custom [CUDA kernels](https://developer.nvidia.com/cuda-zone) * Acceleration using AMD ROCm [linear algebra libraries](https://rocsparse.readthedocs.io/en/master/) and custom [HIP kernels](https://rocmdocs.amd.com/en/latest/ROCm_API_References/HIP-API.html) * Acceleration using Intel OneAPI [oneMKL](https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/onemkl.html) and custom [SYCL kernels](https://software.intel.com/content/www/us/en/develop/tools/oneapi.html) * GPU out-of-core algorithms using the [UTK MAGMA library](http://icl.cs.utk.edu/magma/) * Basic [Python matplotlib](https://matplotlib.org/) support * Fully featured [MATLAB/Octave](https://www.gnu.org/software/octave/) interface via wrappers around the command-line tool * Fortran 2003 interface using [gfortran](https://gcc.gnu.org/wiki/GFortran), [flang](https://flang.llvm.org/docs/), [ifort](https://software.intel.com/en-us/intel-compilers), [pgfortran](https://www.pgroup.com/index.htm), [xlf2003](https://www.ibm.com/products/xl-fortran-linux-compiler-power) * Addon templates for the [Message Passing Interface (MPI)](https://en.wikipedia.org/wiki/Message_Passing_Interface) * [Doxygen](http://www.doxygen.org/) documentation **Note:** with the exception of the MAGMA library and some of the more exotic compilers, the rest of the software is included in most Linux distributions (or HomeBrew) or there are vendor supported software repositories. | Feature | Tested versions | Recommended | |----|----|----| | gcc | 11 - 13 | any | | clang | 14 - 18 | any | | cmake | 3.19 - 3.25 | 3.22 | | python | 3.10 - 3.12 | any | | anaconda| 5.3 | 5.3 | | OpenBlas| 0.2.18 - 3.08 | any | | ESSL | 6.2 | 6.2 | | CUDA | 11.8 - 12.6 | avoid 12.3-12.4 | | ROCm | 5.7 - 6.2 | any | | DPC++ | 2024.2 | 2024 | | libiomp | 5.0 | 5.0 | | MAGMA | 2.5.1 - 2.6.1 | 2.6.1 | | Doxygen | 1.8.13 | 1.8.13 | | MPI | 2.1, 3.1 | 3.1 | ### Install using CMake: the preferred way The preferred way to install Tasmanian is to use the included CMake build script, which requires CMake version 3.19, ROCm capabilities require CMake 3.21. * The commands for an out-of-source CMake build: ``` mkdir Build cd Build cmake make make test make install make test_install ``` * Standard CMake options are accepted: ``` -D CMAKE_INSTALL_PREFIX:PATH= (install folder for the make install command) -D CMAKE_BUILD_TYPE:STRING= (set debug flags or default optimization flags) -D BUILD_SHARED_LIBS:BOOL= (pick shared or static libs) -D CMAKE_CXX_COMPILER:PATH= (specify the C++ compiler, or HIP/ROCm compiler) -D CMAKE_CUDA_COMPILER:PATH= (specify the CUDA nvcc compiler) -D CMAKE_CXX_FLAGS:STING= (set additional flags) ``` * List of Tasmanian specific CMake options (all default to **OFF**): ``` -D Tasmanian_ENABLE_OPENMP:BOOL= (recommended) -D Tasmanian_ENABLE_BLAS:BOOL= (recommended) -D Tasmanian_ENABLE_PYTHON:BOOL= (recommended) -D Tasmanian_ENABLE_RECOMMENDED:BOOL= (enable the above and the -O3 flag) -D Tasmanian_ENABLE_CUDA:BOOL= (stable) -D Tasmanian_ENABLE_HIP:BOOL= (stable) -D Tasmanian_ENABLE_DPCPP:BOOL= (stable) -D Tasmanian_ENABLE_MAGMA:BOOL= (stable) -D Tasmanian_MATLAB_WORK_FOLDER:PATH="" (stable) -D Tasmanian_ENABLE_DOXYGEN:BOOL= (stable) -D Tasmanian_ENABLE_FORTRAN:BOOL= (stable) -D Tasmanian_ENABLE_MPI:BOOL= (stable) ``` * Acceleration options: * OpenMP allows Tasmanian to use more than one CPU core, which greatly increases the performance. While many of the Tasmanian algorithms have been parallelized, the buildin C++ algorithms are usually sequential. This is most notable in the case of `std::sort` but affects others as well. Some compilers support parallel standard algorithms but those in turn reuqire additional compiler flags. * for GCC add `-D_GLIBCXX_PARALLEL` to the `CMAKE_CXX_FLAGS` * Basic Linear Algebra Subroutines (BLAS) is a standard with many implementations, e.g., [https://www.openblas.net/](https://www.openblas.net/); optimized BLAS improves the performance when using evaluate commands on grids with many points or working with models with many outputs * Linear Algebra PACKage (LAPACK) is a set of advanced solver, eigen-solvers and decomposition methods that build upon BLAS and is usually included in the same package, e.g., OpenBLAS, MKL and ESSL; within Tasmanian, the name BLAS in CMake or run-time options indicate the dependence and usage of both BLAS and LAPACK * CUDA is a C++ language extension that allows Tasmanian to leverage the computing power of Nvidia GPU devices, which greatly enhances the performance of `evaluateFast()` and `evaluateBatch()` and a few other calls * HIP/ROCm is very similar to CUDA but uses AMD GPU devices instead, Tasmanian supports a HIP backend * SYCL/DPC++/OneAPI is the Intel alternative to CUDA and HIP, Tasmanian supports a SYCL/DPC++ backend * Matrix Algebra on GPU and Multicore Architectures (MAGMA) is a library for GPU accelerated linear algebra developed at the University of Tennessee at Knoxville * MPI allows the use of distributed memory in Bayesian inference, parallel surrogate model construction, and send/receive grid through an MPI communicators * The **Tasmanian_ENABLE_RECOMMENDED** option searches for OpenMP, BLAS, and Python, enables the options (if possible) and also sets the `-O3` flag * **Tasmanian_ENABLE_FORTRAN** enables the Fortran 2003 interface * Fortran 90 interface is deprecated, but can be enabled with **-DTasmanian_ENABLE_FORTRAN90=ON** * Additional interfaces are available, beyond the default C/C++ library and the command line tools: * Python and Fortran require appropriate interpreter and compiler * The MATLAB/Octave interface requires a work-folder with read/write permission for temporary files. The interface is enabled by setting **Tasmanian_MATLAB_WORK_FOLDER** to a valid read/write location. * The Doxygen option will build the HTML documentation * Options to adjust the testing environment: by default Tasmanian testing will use the system provided OpenMP parameters and run tests on all visible GPU devices; specific number of threads and device can be selected (note that only the testing environment is affected): ``` -D Tasmanian_TESTS_OMP_NUM_THREADS= (only used with OpenMP) -D Tasmanian_TESTS_GPU_ID= (only used with CUDA) ``` * Additional commands to guide the CMake `find_package()` modules: ``` -D Python_EXECUTABLE:PATH (specify the Python interpreter) -D CMAKE_CUDA_COMPILER:PATH (specify the CUDA nvcc compiler) -D Tasmanian_ENABLE_ROCM:PATH (specify the search path for HIP) -D CMAKE_Fortran_COMPILER:PATH (specify the Fortran compiler) -D MKLROOT:PATH (specify the path to the oneMKL installation) -D Tasmanian_MAGMA_ROOT:PATH (specify the path to the MAGMA installation) -D MPI_CXX_COMPILER:PATH= (specify the MPI compiler wrapper) -D MPI_Fortran_COMPILER:PATH= (needed for MPI with Fortran) -D MPIEXEC_EXECUTABLE:PATH= (needed for MPI testing) ``` * The MAGMA option can be passed without the *Tasmanian_* prefix and if not specified explicitly, it will be read from the OS environment. * Option for automated download of MAGMA, the package will be downloaded, build, and installed together with Tasmanian in the same prefix. ``` -D Tasmanian_MAGMA_DOWNLOAD:BOOL= (works only on Linux) ``` * The **ROCm** capabilities **NO LONGER** require the CMake CXX compiler to be set to *hipcc*. * by default, Tasmanian will search for hip in `/opt/rocm /opt/rocm/hip` following the [ROCm documentation](https://rocmdocs.amd.com/en/latest/Installation_Guide/Using-CMake-with-AMD-ROCm.html) * additional search paths can be added using `CMAKE_PREFIX_PATH` * the CXX compiler, if not set automatically, should be set to ROCm clang, e.g., `/opt/rocm/llvm/bin/clang++` * if `Tasmanian_ENABLE_ROCM` is defined and set to a directory, it will be added to `CMAKE_PREFIX_PATH` to search for `roc::hip` * The **OneAPI** capabilities require: * the compiler has to be set to Intel *ipcx*, Tasmanian will automatically add the *-fsycl* flag (when needed) * `Tasmanian_ENABLE_BLAS` is set to **ON** * BLAS is set to the CPU version of MKL, e.g., using `BLAS_LIBRARIES` or `BLA_VENDOR` or `MKLROOT` environment variable * Alternatives allowing to directly specify libraries and bypass `find_package()` altogether: ``` -D BLAS_LIBRARIES -D LAPACK_LIBRARIES ``` * Extra options are available in case CMake fails to find a required dependency, e.g., `find_package()` sometimes fails to acknowledge that the ACML implementation of BLAS depends on both `libgfortran` and `libgomp`; the manual options below should not be necessary in the majority of cases: ``` -D Tasmanian_EXTRA_LIBRARIES:LIST (add more libraries as dependencies) -D Tasmanian_EXTRA_INCLUDE_DIRS:PATH (add more include paths to search for headers) -D Tasmanian_EXTRA_LINK_DIRS:PATH (appends more link paths to search for libraries) ``` * Options helpful to Tasmanian developers: ``` -D DOXYGEN_INTERNAL_DOCS=YES (include the documentation of the Tasmanian internals) ``` ### Install with (basic) GNU Make The core capabilities of Tasmanian can be build with a few simple GNU Make commands. The basic build engine is useful for quick testing and exploring Tasmanian, or if CMake is unavailable or unwanted. Acceleration options other than OpenMP are not supported in the basic mode, CMake is so common these days that it should be the default way to install. * Using GNU Make with `g++` and optionally `/usr/bin/env python` ``` make make test (will fail if /usr/bin/env python is missing the numpy or ctypes modules) make matlab (optional: sets matlab work folder to ./tsgMatlabWorkFolder/) make examples make clean ``` In the basic mode, the source folder will become the installation folder, i.e., the libraries, executables and Python modules will be build in the source folder and the headers will be copied to the `include` sub-folder. ### Install with Python Pip Tasmanian is included in the Python Pip index: [https://pypi.org/project/Tasmanian/](https://pypi.org/project/Tasmanian/) ``` python3 -m pip install Tasmanian --user (user installation) python3 -m pip install Tasmanian (virtual env installation) ``` The Tasmanian module is not a regular Python-only project but a wrapper around the C++ libraries, note the following: * The compiled binaries are cached by pip and `--no-cache-dir` option must be used to change the options. * Only user installations are supported, installation for all users is possible with CMake but not Pip. * Python virtual environments are supported, as well as Linux, Mac and Windows operating systems. * By default, Tasmanian will install with `Tasmanian_ENABLE_RECOMMENDED=ON` which will safe-auto-enable BLAS and OpenMP * environment variable (see below) can be used to disable the recommended options and switch to manual enable/disable * The Pip installer will accept Tasmanian options specified in the environment variables: ``` Environment Option will translate to CMake Options export Tasmanian_ENABLE_RECOMMENDED=OFF -D Tasmanian_ENABLE_RECOMMENDED=OFF export Tasmanian_ENABLE_BLAS= -D Tasmanian_ENABLE_BLAS=ON -D BLAS_LIBRARIES= -D LAPACK_LIBRARIES= export Tasmanian_ENABLE_CUDA= -D Tasmanian_ENABLE_CUDA=ON -D CMAKE_CUDA_COMPILER= export Tasmanian_ENABLE_DPCPP= -D Tasmanian_ENABLE_DPCPP=ON -D CMAKE_CXX_COMPILER= export Tasmanian_ENABLE_MAGMA= -D Tasmanian_ENABLE_MAGMA=ON -D Tasmanian_MAGMA_ROOT_DIR= export Tasmanian_ENABLE_MPI= -D Tasmanian_ENABLE_MPI=ON -D MPI_CXX_COMPILER= export Tasmanian_MATLAB_WORK_FOLDER= -D Tasmanian_MATLAB_WORK_FOLDER= ``` * CMake also accepts several standard environment variables: ``` Environment Option Example values export BLA_VENDOR OpenBLAS or MKL export MKLROOT /opt/intel/oneapi/mkl/latest ``` * note that the Tasmanian specific environment variables work only with Python Pip * Example virtual install looks like this: ``` python3 -m venv tasmanian_virtual_env # create a virtual environment source ./tasmanian_virtual_env/bin/activate # activate the virtual environment export Tasmanian_ENABLE_CUDA=/usr/local/cuda/bin/nvcc # specify the CUDA compiler python -m pip install Tasmanian --no-cache-dir # will install Tasmanian with CUDA python -m Tasmanian # print the install log tasgrid -v # print the available CUDA devices ``` Additional notes: * under MS Windows the environment variables can be set from Advanced System Settings, but the paths should use Linux style of back-slashes, e.g., `C:/Program Files/CUDA/bin/nvcc.exe` * scikit build sometimes lags in support for the latest MS Visual Studio, regular CMake install works fine * under OSX some users have reported segfaults when using a pip install, the problem does not appear when using CMake, the issue is under investigation ### Install with Spack Tasmanian is also included in Spack: [https://spack.io/](https://spack.io/) ``` spack install tasmanian+openmp+blas+cuda+magma+python+fortran ``` ### Install on MS Windows platform Tasmanian has been tested with MS Visual Studio 2019. * First use the CMake GUI to set the folders and options * Then use the command prompt (`cmd.exe`) to enter the build folder ``` cd cmake --build . --config Release ctest -C Release cmake --build . --config Release --target install ``` * Both Debug and Release are supported config modes, but do not use them simultaneously, pick only one Release or Debug. ### Install on Mac platform As of Tasmanian 8.1, the Mac OSX installation handles the same as Linux regardless for both Intel and M-chips. ### Install folder structure Tasmanian follows standard Linux conventions, the install path could be set to `/usr/local/`, although it is recommended to install in a location inside the user home folder to avoid potential system-wide conflicts. * Install folder structure: ``` /bin/ (tagrid executable tool) /lib/ (shared or static libraries) /lib/Tasmanian/ (cmake package-config files) /lib/pythonX.Y/ (python module) /include/ (headers .h and .hpp, and Fortran .mod) /share/Tasmanian (bash env scripts, install log, table) /share/Tasmanian/examples/ (reference examples) /share/Tasmanian/matlab/ (matlab scripts) /share/Tasmanian/python/ (copy of /lib/pythonX.Y) /share/Tasmanian/testing/ (a CMake script for post-install testing) ``` Additional notes: * A summary of all compile options is stored in ``` /share/Tasmanian/Tasmanian.log ``` * The log file can be displayed with wither command: ``` /bin/tasgrid -log (using the command line tool) python -m Tasmanian (only if Python is enabled) ``` * The executable and library paths, as well as the Python path can be set in `bash` by sourcing ``` source /share/Tasmanian/TasmanianENVsetup.sh ``` * When using pip, the python module location may be different depending on the OS and the Python virtual environment. * The Python module is version independent, i.e., the files work with all tested Python versions; the `share/Tasmanian/python` copy allows for easy and version independent access to the Tasmanian modules. * Under MS Windows the shared libraries (e.g., the .dll files) are installed in `bin`. ### Linking to Tasmanian: CMake Package Config Tasmanian will install CMake package-config files in `/lib/Tasmanian`, the files will contain all necessary information to import the Tasmanian targets into other CMake projects using the CMake command: ``` find_package(Tasmanian 8.1 PATHS "") ``` See the included `CMakeLists.txt` in `/share/Tasmanian/examples`. Note that the `PATHS` do not have to be specified explicitly if the `TasmanianENVsetup.sh` is sourced or if the `Tasmanian_ROOT` environment variable is set. The correct `find_package()` command is displayed in the log (see the previous section). The imported targets will be named: ``` Tasmanian::Tasmanian (links to the C++ libraries) Tasmanian::tasgrid (imported executable pointing to the command line tool) Tasmanian::Fortran (links to the C++ libraries and the Fortran wrappers) ``` In addition, the following variables will be set: ``` Tasmanian_PYTHONPATH (path to the Python module, if Python was enabled) Tasmanian_MATLAB_WORK_FOLDER (path to the MATLAB work folder, if set during build) Tasmanian_MATLABPATH (path to the MATLAB scripts, if MATLAB was enabled) Tasmanian__FOUND (set to ON for each available component) ``` The possible components are: ``` SHARED STATIC OPENMP BLAS CUDA HIP DPCPP MAGMA MPI PYTHON MATLAB FORTRAN ``` The modules correspond to shared and static libraries and the cmake options used during build. All available components will be included even if the component is not explicitly requested. Requesting components can help catch errors early in the build process and/or print useful log messages. For example: ``` find_package(Tasmanian 8.1 REQUIRED SHARED PYTHON CUDA OPTIONAL_COMPONENTS OPENMP) ``` In the above example: * an error will be generated if Tasmanian was build with static libraries, no CUDA or no Python support * a status message will report whether Tasmanian was build with OpenMP support * requesting incompatible components will always fail, e.g., CUDA with ROCM or SHARED and STATIC ### Known Issues Several known issues and work-around fixes: * Apple OSX has poor support for OpenMP, especially when using M-chips (apple silicon) * OpenMP is not supported by the default compiler (xcode) * gcc with OpenMP support can be installed through Homebrew, but the performance gains from multi-threading are low * the automated MAGMA download reports the wrong GPU architecture enabled * ignore the MAGMA message the build correctly respects `CMAKE_CUDA_ARCHITECTURES` * The addon tests sometime fail due to thread scheduling * The overhead associated with thread scheduling is much larger than the simple test models used, which leads to unrealistically large fluctuations in sample run-time, which in turn leads to randomness in the results, most notably on machines with few cpu cores. * Rerun the tests and/or installation to see if the problem is persistent * Mixing the GCC and Clang compilers and linkers sometimes fails with an error about the architecture * use shared libraries only, i.e., `-D BUILD_SHARED_LIBS=ON` in CMake * Some older versions of the PGI compiler fails when using optimization `-O2` * use the `-O1` instead, or the newest version of the compiler * CUDA 12.3 and 12.4 seem to have a bug in cuSparse * whenever possible, avoid those versions of CUDA TASMANIAN-8.1/Doxygen/InterfaceCLI.md000066400000000000000000000210121470551176200170700ustar00rootroot00000000000000# Command Line Interface The **tasgrid** executable is a command line interface to the Tasmanian Sparse Grid module. It provides the ability to create and manipulate sparse grids, save and load them into files and optionally interface with another program via text files. For the most part, **tasgrid** reads a grid from a file, calls one or more of the functions described in the previous section and then saves the resulting grid. The commands for **tasgrid** correspond to calls to the C++ API, where scalar inputs are given as command line arguments and vector/array parameters are given as matrix files, see the end of this section for the matrix file format. ``` ./tasgrid .... ``` The first input to the executable is the command that specifies the action that needs to be taken. The command is followed by options and values. Every command is associated with a set of options, extra options are ignored. See the help subsection on how to find the right options for each command. ### Example commands ``` ./tasgrid -mq -dim 4 -depth 2 -type qptotal -1d gauss-legendre -p ``` Make quadrature rule in 4 dimensions that can integrate exactly all quadratic polynomials, print the result to the screen. Note that the first column is the weight. ``` ./tasgrid -mg -dim 3 -out 2 -depth 4 -type iptotal -1d clenshaw-curtis -gf example_grid_file ./tasgrid -l -gf example_grid_file -vf file_with_values ./tasgrid -e -gf example_grid_file -xf file_with_points -of result_file ``` The first command creates a global grid with 3 dimensions and clenshaw-curtis points that interpolate exactly all polynomials of order 4. The grid is stored in *example_grid_file*. In the second command, model values are read from the *file_with_values* and loaded into the grid. In the final command, the interpolant is evaluated at the points specified in *file_with_points* and the result is stored in the last file. ### Command: -h, help, -help, --help ``` ./tasgrid --help ./tasgrid -makequadrature help ``` Prints information about the usage of **tasgrid**. In addition, writing **help** after any command will print information specific to that command; effectively, **help** is a universal option. ### Commands and corresponding C++ functions ``` ./tasgrid -makeglobal -> makeGlobalGrid() ./tasgrid -makesequence -> makeSequenceGrid() ./tasgrid -makelocalpoly -> makeLocalPolynomialGrid() ./tasgrid -makewavelet -> makeWaveletGrid() ./tasgrid -makefourier -> makeFourierGrid() ./tasgrid -makequadrature -> (one of the grids above, see comments) ./tasgrid -makeupdate -> updateGlobalGrid()/updateSequenceGrid() ./tasgrid -setconformal -> setConformalTransformASIN() ./tasgrid -getquadrature -> getQuadratureWeights()/getPoints() ./tasgrid -getinterweights -> getInterpolationWeights() ./tasgrid -getdiffweights -> getDifferentiationWeights() ./tasgrid -getpoints -> getPoints() ./tasgrid -getneededpoints -> getNeededPoints() ./tasgrid -loadvalues -> loadNeededPoints() ./tasgrid -evaluate -> evaluateBatch() ./tasgrid -evalhierarchyd -> evaluateHierarchicalFunctions() ./tasgrid -evalhierarchys -> evaluateSparseHierarchicalFunctions() ./tasgrid -integrate -> integrate() ./tasgrid -differentiate -> differentiate() ./tasgrid -getanisotropy -> estimateAnisotropicCoefficients() ./tasgrid -refineaniso -> setAnisotropicRefinement() ./tasgrid -refinesurp -> setSurplusRefinement() ./tasgrid -refine -> setAnisotropicRefinement()/setSurplusRefinement() ./tasgrid -cancelrefine -> clearRefinement() ./tasgrid -mergerefine -> mergeRefinement() ./tasgrid -getcoefficients -> getHierarchicalCoefficients() ./tasgrid -setcoefficients -> setHierarchicalCoefficients() ./tasgrid -getpoly -> getGlobalPolynomialSpace() ./tasgrid -summary -> printStats() ./tasgrid help -> show more info for this command ``` Additional notes: * The domain types for all grids are set during the *make* command, domains cannot be changed with the **tasgrid** executable since domain changes always change the nodes and effectively generates a new grid. * Make quadrature creates a grid with zero outputs and type that is based on the one dimensional rule, e.g., the **-makeupdate** grid will automatically detect sequence or global grids. * The **-getquadrature** command will generate larger matrix, where the first column is the weights and the rest correspond to the points. * The **-getinterweights** and **-getdiffweights** commands can work with multiple points at a time, the call will use OpenMP (if available). * The **-refine** command will call anisotropic refinement on Global, Sequence, and Fourier grids, and surplus refinement for Local Polynomial and Wavelet grids. * The coefficients and hierarchical functions for Fourier grids work with complex numbers, meaning that each pair of consecutive numbers correspond to one complex number (real and complex parts). This the matrices have twice as many columns. Note that this also applies to the coefficients as inputs and outputs (which is different from the C++ API). * The **-evaluate** command accepts **-gpuid** options, which allows to select a CUDA device to use for acceleration. If the option is omitted, GPU acceleration will not be used. ### Command: -listtypes ``` ./tasgrid -listtypes ``` List the available one dimensional quadrature and interpolation rules as well as the different types of grids, refinement and conformal mapping types. Use this command to see the correct spelling of all string options. ### Command: -version or -info ``` ./tasgrid -version ./tasgrid -v ./tasgrid -info ``` Prints the version of the library, the available acceleration options, and (if CUDA is enabled) the visible CUDA devices. ### Command: -test ``` ./tasgrid -test ./tasgrid -test random ./tasgrid -test verbose ``` Since Tasmanian 6.0 the sparse grids testing is moved to a different executable, i.e., **gridtest**. The test method of **tasgrid** is still included but it covers only a sub-set of the tests. Also, the tests take longer, especially when CUDA is enables, since large reference solutions have to be computed on the slower CPU. The **gridtest** executable takes the **random** and **verbose** switches, but does not need the **-test** command. The tests rely on random number generation to estimate the accuracy of computed interpolants. If the test fails, this may be indication of a problem with the hard-coded random seed. Using the **random** option will reset the seed on every run and will provide more statistically significant results. The **verbose** will print more detailed output. This affects only the successful tests, failed tests always print verbose information. ### Matrix File Format The matrix files have two formats, binary and ASCII. The simple text file describes a two dimensional array of real (double-precision) numbers. The file contains two integers on the first line indicating the number of rows and columns. Those are followed by the actual entries of the matrix one row at a time. The file containing ``` 3 4 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 ``` represents the matrix \f$ \left( \begin{array}{rrrr} 1 & 2 & 3 & 4 \\ 5 & 6 & 7 & 8 \\ 9 & 10 & 11 & 12 \\ \end{array} \right) \f$ A matrix file may contain only one row or column, e.g., ``` 1 2 13.0 14.0 ``` In binary format, the file starts with three characters *TSG* indicating that this is a binary Tasmanian file. The characters are followed by two integers and the double-precision numbers that correspond to the matrix being read left-to-right top-to-bottom. All files used by **tasgrid** have the above format with three exceptions. The **-gridfile** option contains saved sparse grids and it is not intended for editing outside of the **tasgrid** calls (it is OK to modify using other Tasmanian API calls, e.g., C++ or Python). The **-anisotropyfile** option requires a matrix with one column and it should contain double-precision numbers that have integer values. The **-customrulefile** has special format is described the Custom Rule File Format section. The default mode is to use binary files for all calls to **tasgrid**, but ASCII files are easier to debug and potentially easier to import to external codes. This **tasgrid** has an option **-ascii** that can be added to any command and will force the resulting output to be written in ASCII format. TASMANIAN-8.1/Doxygen/InterfaceFortran2003.md000066400000000000000000000173751470551176200204220ustar00rootroot00000000000000# Interface Fortran 2003 Tasmanian comes with Fortran 2003 interface generated by [Swig-Fortran](https://github.com/swig-fortran). The automatic generation makes the code easy to maintain and support, and the generation process is done off-line by the development team; hence, users are not required to install Swig and can use the interface with just a regular Fortran compiler. Furthermore, the 2003 standard support objects which allows for the OOP interface of Tasmanian C++ to be duplicated similar to Python and thus the on-line C++ Doxygen documentation is now relevant to Fortran as well. The new module is called `Tasmanian` (without the sg suffix), and it is incompatible with the Fortran 90/95, i.e., use one or the other but not both. A `TasmanianSparseGrid` type is introduced as before, but the interface is fully object-oriented. Currently, the Tasmanian Sparse Grid module has been implemented together with the MPI Addons; the Dream module and the remainder of the Addon templates are not supported (possibly in the future). Simple example: ``` program tasmanian_demo use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:,:), allocatable :: points integer :: i, j grid = TasmanianSparseGrid() call grid%makeGlobalGrid(2, 1, 1, tsg_type_level, tsg_rule_clenshawcurtis) allocate(points(grid%getNumDimensions(), grid%getNumPoints())) call grid%getPoints(points(:, 1)) do i = 1, grid%getNumDimensions() do j = 1, grid%getNumPoints() write(*,*) points(i, j) enddo enddo deallocate(points) call grid%release() end program tasmanian_demo ``` Line by line: * The `TasmanianSparseGrid` object must be initialized and deleted with the commands ``` grid = TasmanianSparseGrid() call grid%release() ``` * The make-grid commands have the same syntax as C++ with the enumerate types replaced by integer constants with identical names and the `tsg_` prefix. * The double-precision type used in all calls is `real(C_DOUBLE)` but it could easily be the Fortran native `DOUBLE PRECISION` so long as the type is compatible with `C_DOUBLE`. * The organization of the points is in two dimensional matrix, where each column corresponds to the coordinates of a single point; however, the API accepts only single dimensional arrays (c-style), hence the conversion ``` call grid%getPoints(points(:, 1)) ``` ### See the Included Examples Several Fortran examples are provided that duplicate the functionality in C++ and Python, which makes it easy to compare and contrast. ### Filenames and Strings Strings works differently between the Fortran, C and C++ languages. Tasmanian I/O methods accept C-style of null-terminated character arrays, but Fortran character arrays are often padded with white spaces. The Fortran `trim()` command can be used to remove trailing white spaces from the filenames and avoid confusion with C++. See the following example that assumes a file with the name "123" is holding a valid Tasmanian sparse grid and we want to read the grid into a Tasmanian object: ``` character(len = 3), parameter :: filename = "123" character(len = 4), parameter :: padded = "123" grid = TasmanianSparseGrid() grid%read(filename) ! OK, reads from "123" ! grid%read(padded) ! Bad, tries to read from "123 " grid%read(trim(padded)) ! OK, removes the extra space ``` ### Row-vs-Column Format C and C++-14 standards do not have a native two dimensional data-structure and many of the inputs and outputs for Tasmanain are logically organized in strips of data with a fixed stride. When interfacing with a language that supports two dimensional data (e.g., matrix type) it is beneficial to make the translation, but without a copy or manual transposing of the data to avoid performance degradation. Therefore, the strips of data are aligned to the dimension of the fastest index, e.g., the rows for a row-major language (Python-numpy) and columns for a column-major one (Fortran). The Matlab interface uses row-major format due to the ascii file standard used in the background. The five point Clenshaw-Curtis grid has 5 points, `(0,0)`, `(0,-1)`, `(0,1)`, `(-1,0)` and `(1,0)`. The matrix generated by Fortran will have the organization: ``` 0 0 0 -1 1 0 -1 1 0 0 ``` while the Python and Matlab equivalents would be: ``` 0 0 0 -1 0 1 -1 0 1 0 ``` ### Factory and Helper Methods and Namespaces Fortran 2003 does not support namespaces and the wrapper API works directly with user allocated matrices. The `make***Grid()` factory methods have been replaced with: ``` TasGrid::makeGlobalGrid => TasmanianGlobalGrid TasGrid::makeSequenceGrid => TasmanianSequenceGrid TasGrid::makeLocalPolynomialGrid => TasmanianLocalPolynomialGrid TasGrid::makeFourierGrid => TasmanianFourierGrid TasGrid::makeWaveletGrid => TasmanianWaveletGrid TasGrid::readGrid => TasmanianReadGrid TasGrid::copyGrid => TasmanianCopyGrid ``` Although the methods do not support array API and hence anisotropic weights and level limits still require the use of the member functions, e.g., `makeGlobalGrid()`. The static array API works with allocatable variables but requires user allocation of memory and is not very expressive. Functions that return pointers to pre-allocated data are preferable; however, functions and subroutines cannot share names in generic overloads. Thus, the Fortran functions use alternative names that start with `return` as opposed to `get`, e.g., ``` real(C_DOUBLE), dimension(:,:), pointer :: points ... points => grid%returnPoints() ... deallocate(points) ``` The helper function are: ``` points => grid%returnLoadedPoints() points => grid%returnNeededPoints() points => grid%returnPoints() weight => grid%returnQuadratureWeights() coeffs => grid%returnHierarchicalCoefficients() coeffs => grid%returnComplexHierarchicalCoefficients() ``` See the next section for complex numbers. ### Complex numbers Tasmanian Fourier grids utilize complex numbers in the background which is usually opaque to the user. However, the methods to set and get hierarchical coefficients do use complex numbers, see the C++ API for details. The C++ API returns raw pointers which cannot be manipulated directly from within Fortran; hence the C++ methods are replaced with methods that accept and return copies of the data and utilize the complex format (similar to Python and MATLAB). The two methods are: ``` complex(C_DOUBLE), dimension(:, :), pointer :: coeffs, new_coeffs ... coeffs => grid%returnComplexHierarchicalCoefficients() grid%setComplexHierarchicalCoefficients(new_coeffs) ``` ### MPI Fortran Capabilities If Tasmanian has been compiled with MPI support, a second Tasmanian module will be included that contains Fortran wrappers for the MPI C++ templates. The module is called `Tasmanian_mpi` and must be used in conjunction with `Tasmanian`, e.g., ``` use Tasmanian use Tasmanian_mpi use mpi ``` The `Tasmanian_mpi` module instantiates the templates as Fortran functions and pre-pends `tsg` to the names to avoid possible namespace conflicts, e.g., ``` ierr = tsgMPIGridSend(grid, destination, tag, comm) ierr = tsgMPIGridRecv(grid, source, tag, comm) ierr = tsgMPIGridBcast(grid, root, comm) ierr = tsgMPIGridScatterOutputs(grid, subgrid, root, tag, comm) ``` Note, each methods returns the MPI error code returned by C++ which is different from the way MPI usually works under Fortran, but that is due to the way Swig instantiates the templates and the fact that the error comes from MPI call in the C++ section of the code. The templates always work in binary communication mode, since the ASCII mode is mostly for debugging purposes on the C++ side. TASMANIAN-8.1/Doxygen/InterfaceLibEnsemble.md000066400000000000000000000066731470551176200206620ustar00rootroot00000000000000# libEnsemble Integration Tasmanian has integration with the [libEnsemble](https://github.com/Libensemble/libensemble) project, which is a Python library to coordinate the concurrent evaluation of dynamic ensembles of calculations. The workflow management system of libEnsemble can be wrapped around the Tasmanian sparse grid methods for constructing surrogate models and libEnsemble can serve as an intermediary between Tasmanian and the model of interest. The functionality provided by libEnsemble is similar to that of `TasGrid::constructSurrogate()` and `TasGrid::mpiConstructSurrogate()`. While the native Tasmanian methods are functional, libEnsemble provides much more sophisticated workflow algorithms and much wider support for hardware architectures. One of the main advantages of libEnsemble is that the code is portable on shared memory multi-threaded environments, as well as numerous distributed cluster systems. ### Requirements Using Tasmanian and libEnsemble together requires: * Tasmanian 7.0 or newer * Tasmanian Python bindings are enabled, e.g., with `Tasmanian_ENABLE_PYTHON=ON` or the pip-installer * libEnsemble from the latest development branch * see the [libEnsemble](https://github.com/Libensemble/libensemble) documentation for any additional requirements ### Installation The easiest way to install the latest development version of libEnsemble is to clone the repo and use a local pip-installer: ``` git clone https://github.com/Libensemble/libensemble.git cd libensemble git checkout develop python3 setup.py sdist python3 -m pip uninstall libensemble python3 -m pip install dist/*.tar.gz ``` See the [Installation](Doxygen/Installation.md) instructions for Tasmanian. Notes: * the `pip` approach required both `git` and the Python `pip` modules to be installed * see also the libEnsemble instructions for more details * both Tasmanian and libEnsemble works well within a Python `venv` environment ### Basic Usage An example of the Tasmanian-libEnsemble integration can be found in the [libEnsemble testing suite](https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_tasmanian.py). The Tasmanian sparse grid construction algorithm is implemented as the `sparse_grid_batched` libEnsemble native `gen_f` function: ``` from libensemble.gen_funcs.persistent_tasmanian import sparse_grid_batched as gen_f_batched ``` The construction method accepts the following user parameters: ``` gen_specs['user']['tasmanian_init'] -> a callable function with no inputs that returns an initialized object of Tasmanian.SparseGrid gen_specs['user']['tasmanian_checkpoint_file'] -> a file for intermediary check pointing as well as the final grid ``` No additional parameters are required for static grid construction, e.g., similar to `TasGrid::loadNeededPoints()`. Iterative refinement can be enabled with the additional options for either anisotropic strategy ``` gen_specs['user']['refinement'] = 'setAnisotropicRefinement' gen_specs['user']['sType'] = 'iptotal' gen_specs['user']['iMinGrowth'] = 10 gen_specs['user']['iOutput'] = 0 ``` or surplus strategy ``` gen_specs['user']['refinement'] = 'setSurplusRefinement' gen_specs['user']['fTolerance'] = 1.E-2 gen_specs['user']['sCriteria'] = 'classic' gen_specs['user']['iOutput'] = 0 ``` See `TasGrid::TasmanianSparseGrid::setAnisotropicRefinement()` and `TasGrid::TasmanianSparseGrid::setSurplusRefinement()` for details. TASMANIAN-8.1/Doxygen/InterfaceMATLAB.md000066400000000000000000000232561470551176200174350ustar00rootroot00000000000000# MATLAB/Octave Interface The Matlab or Octave interface to **tasgrid** consists of several functions that call various **tasgrid** commands and read and write matrix files. Unlike most Matlab interfaces, this is code does not use .mex files, but rather system commands and text files. In a nut shell, Matlab **tsgMakeXYZ** functions take a user specified name and create a Matlab object and a file generated by **tasgrid** option **-gridfile** (or **TasmanianSparseGrid::write()** function). The Matlab object is used to reference the specific grid file and is needed by most other functions. Here are some notes to keep in mind: * The interface requires that Matlab is able to call external commands, specifically the **tasgrid** executable. * The interface also requires access to a folder where the files can be written. * The Matlab work folder option in CMake allows you to automatically specify where the temporary files will be stored. The *make matlab* target in the GNU make engine sets the work folder in a sub-folder of the Tasmanian source directory. In either case, the default folder can be changed by manually editing **tsgGetPaths.m**. * Each grid has a user specified name, that is a string which gets pre-pended at the beginning of the file name. * Any Tasmanian grid file can be loaded into a MATLAB object using the **c** function * The **tsgDeleteGrid()**, **tsgDeleteGridByName()** and **tsgListGridsByName()** functions allow for cleaning the files in the temporary folder. * Every Tasmanian-Matlab function corresponds to one **tasgrid** command. * Every function comes with help comments that can be accessed by typing ``` help tsgFunctionName ``` * Note that it is recommended to add the folder with the Tasmanian interface to the Matlab path, otherwise the **addpath()** command has to be called after every restart. * All input variables follow naming convention where the first character specifies the type of the variable: * **i** stands for integer * **s** stands for string * **f** stands for real number * **l** stands for list * **v** stands for vector, i.e., row or column matrix * **m** stands for matrix, i.e., two dimensional array * See the notes about the Fortran 2003 interface regarding the row-major matrix format ### List of Matlab functions and corresponding C++ API ``` tsgCancelRefine.m -> clearRefinement()/finishConstruction() tsgEstimateAnisotropicCoefficients.m -> estimateAnisotropicCoefficients() tsgEvaluateHierarchy.m -> evaluateHierarchicalFunctions() tsgEvaluate.m -> evaluateBatch() tsgGetCandidateConstructionAnisotropic.m tsgGetCandidateConstructionSurplus.m -> getCandidateConstructionPoints() tsgGetHCoefficients.m -> getHierarchicalCoefficients() tsgGetInterpolationWeights.m -> getInterpolationWeights() tsgGetNeededPoints.m -> getNeededPoints() tsgGetPoints.m -> getPoints() tsgGetPolynomialSpaces.m -> getGlobalPolynomialSpace() tsgGetQuadrature.m -> getQuadratureWeights()/getPoints() tsgIntegrate.m -> integrate() tsgLoadHCoefficients.m -> setHierarchicalCoefficients() tsgLoadConstructedPoints.m -> loadConstructedPoints() tsgLoadValues.m -> loadNeededValues() tsgMakeFourier.m -> makeFourierGrid() tsgMakeGlobal.m -> makeGlobalGrid() tsgMakeLocalPolynomial.m -> makeLocalPolynomialGrid() tsgMakeQuadrature.m -> (see tasgrid -makequadrature) tsgMakeSequence.m -> makeSequenceGrid() tsgMakeWavelet.m -> makeWaveletGrid() tsgMergeRefine.m -> mergeRefinement() tsgRefineAnisotropic.m -> setAnisotropicRefinement() tsgRefineSurplus.m -> setSurplusRefinement() tsgSummary.m -> printStats() ``` The Matlab functions wrap around **tasgrid**, thus what applies to one applies to the other. See the **tasgrid** notes about the order of complex Fourier coefficients and make quadrature. ### Function tsgCoreTests() ``` tsgCoreTests() ``` Performs a series of tests of the Matlab interface. If some tests are failing, the installation is incomplete or corrupted. ### Function tsgGetPaths() ``` [ sFiles, sTasGrid ] = tsgGetPaths() ``` This function returns two strings: * **sTasGrid** is a string containing the path to the **tasgrid** executable (including the name of the executable). * **sFiles** is the path to a folder where Matlab has read/write permission. Files will be created and deleted in this folder. ### Function tsgReadMatrix() and tsgWriteMatrix() Those functions are used internally to read from or write to matrix files. Those functions should not be called directly. ### Function tsgCleanTempFiles() Those functions are used internally to clean the temporary files. ### Function tsgListGridsByName() Scans the work folder and lists the existing grids regardless whether those are currently associated with Matlab objects. The names can be used for calls to **tsgDeleteGridByName()** and **tsgReloadGrid()**. ### Function tsgLoadGridFromFile() Takes an existing filename created with any of the Tasmanian interfaces and loads it into an object. The object still needs a unique name for the temporary files, but the file can be anywhere in the system and only needs read/write permissions. Many methods, e.g., **tsgEvaluate()** do not modify the file and work with just read permissions. Note that writing to the file from two interfaces at the same time will likely cause file corruption, simultaneous regarding and writing will probably crash, concurrent reads will work. ``` lGrid = tsgReloadGrid( , ) ``` ### Function tsgDeleteGrid()/tsgDeleteGridByName() Deleting the Matlab object doesn't remove the files from the work folder, thus **tsgDeleteGrid()** has to be explicitly called to remove the files associated with the grid. If the Matlab object has been lost (i.e., cleared by accident), then the grid files can be deleted by specifying just the name for **tsgDeleteGridByName()**, see also **tsgListGridsByName()**. * **WARNING** the **tsgDeleteGrid()** method will delete the file used in **tsgLoadGridFromFile()**. ### Function tsgReloadGrid() Creates a new Matlab object file for a grid with existing files in the work folder. This function can restore access to a grid if the grid object has been lost. This function can also create aliases between two grids which can be dangerous, see the section about avoiding problems. This function can also be used to gain access to a file generated by **tasgrid -gridfile** option or **TasmanianSparseGrid::write()** function, just generate the file, move it to the work folder, rename it to `_FileG`, and call ``` lGrid = tsgReloadGrid( ) ``` ### Function tsgCopyGrid() Creates a duplicate of an existing grid, this function creates a new Matlab object and a new grid file in the work folder. ### Function tsgWriteCustomRuleFile() Writes a file with a custom quadrature or interpolation rule, see the Custom Rule File Format section. ### Function tsgExample() ``` tsgExample() ``` This function contains sample code that mimics the C++ examples and serves as a demonstration on the proper way to call the Matlab functions. ### GPU acceleration ``` lGrid = tsgMakeLocalPolynomial( ... ) lGrid.gpuDevice = 0; result = tsgEvaluate(lGrid, ...) ``` If the **lGrid** object has a **gpuDevice** field, then the corresponding GPU will be used for the evaluations. Run **tsgCoreTest()** to see a list of detected CUDA devices. ### Saving a Grid You can save the **lGrid** object just like any other Matlab object. However, a saved grid has two components, the **lGrid** object and the files associated with the grid that are stored in the folder specified by **tsgGetPath()**. The files in the temporary folder will be persistent until either **tsgDeleteGrid()** is called or the files are manually deleted. The only exception is that the **tsgExample()** function will overwrite any grids with names starting with `_tsgExample1` through `_tsgExample10`. Note that modifying **tsgGetPath()** may result in the code not being able to find the needed files and hence the grid object may be invalidated. ### Avoiding Some Problems * Make sure to call **tsgDeleteGrid()** as soon as you are done with a grid, this will avoid clutter in the temporary folder. * If you clear an **lGrid** object without calling **tsgDeleteGrid()** (i.e., you exit Matlab without saving), then make sure to use **tsgListGridsByName()** and **tsgDeleteGridByName()** to safely delete the *lost* grids. * Working with the Matlab interface is very similar to working with dynamical memory, where the data is stored on the disk as opposed to the RAM and the **lGrid** object is the pointer. Also, the grids are associated by name as opposed to a memory address. * If multiple users are sharing the same temporary folder, then it would be useful if they come up with a naming convention that prevents two users from using the same grid name. For example, instead of both users creating a grid named *mygrid1*, the users should name their grids *johngrid1* and *janegrid1*. * All of the grid data for all of the grids is stored in the same folder. Anyone with access to the temporary folder has full access to all of the sparse grid data. * If two users have separate copies of **tsgGetPaths()**, then they can use separate storage folders without any of the multi-user considerations. This is true even if all other files are shared, including the **tasgrid** executable and Tasmanian libraries. TASMANIAN-8.1/Doxygen/InterfacePython.md000066400000000000000000000131231470551176200177460ustar00rootroot00000000000000# Python Interface The Python interface uses `c_types` and links to the C interface of Tasmanian as well as several additional C-style functions, e.g., when dealing with Addon templates. The C++ classes are converted to `void*` pointers and then wrapped inside Python classes with near identical interface. The C++ vectors are replaced by 1D and 2D `numpy.ndarray` structures, the enumerated types are replaced by strings, and the C++ `std::function` and `lambda` expressions by Python callable objects and lambdas. See the Fortran 2003 comments about the row major matrix format. ### Requirements Python 3 is the only version currently tested and Tasmanian uses the following modules: * **required** `sys` * **required** `c_types` * **required** `numpy` * **optional** `matplotlib.pyplot` Tasmanian is also available through PIP: [https://pypi.org/project/Tasmanian/](https://pypi.org/project/Tasmanian/); however, the PIP installation comes with additional requirements for facilitating the CMake build process. See the PIP section on the installation instructions page. ### Module Starting with Tasmanian 7.0 all Python capabilities are included in a single module: ``` import Tasmanian ``` Note that the Tasmanian install path must be included in the Python search path: ``` /lib/pythonX.Y/site-packages/ # following the Python convention /share/Tasmanian/python/ # Tasmanian version independent path ``` Either path is sufficient if it is added to the environment variable `PYTHONPATH` (e.g., via the `TasmanianENVsetup.sh` script) or with the `sys.path.append()` command. Example for creating an instance of a sparse grid: ``` import Tasmanian grid = Tasmanian.SparseGrid() grid.makeGlobalGrid(...) ``` Example for using DREAM sampling: ``` import Tasmanian state = Tasmanian.DREAM.State(...) state.setState(Tasmanian.DREAM.genUniformSamples(...)) Tasmanian.DREAM.Sample(iNumBurnupIterations, iNumCollectIterations, lambda x : numpy.exp( - x[:,0]**2 ), Tasmanian.DREAM.Domain("unbounded"), state, Tasmanian.DREAM.IndependentUpdate("uniform", 0.5), Tasmanian.DREAM.DifferentialUpdate(90)) ``` See the Python examples in `/share/Tasmanian/examples/`. ### Additional Documentation Every class and method in Tasmanian comes with additional comments designed to be accessed with the Python `help()` function, e.g., ``` help(Tasmanian.SparseGrid.makeGlobalGrid) ``` * Sparse grid module and C++ equivalent: ``` Tasmanian.SparseGrid (class) -> TasGrid::TasmanianSparseGrid (class) Tasmanian.TasmanianSimpleSparseMatrix (class) -> triplet vectors (pntr, indx, vals) ``` * DREAM module and C++ equivalent: ``` import Tasmanian.DREAM as DREAM (class) DREAM.State -> TasDREAM::TasmanianDREAM (class) (class) DREAM.LikelihoodGaussIsotropic -> TasDREAM::LikelihoodGaussIsotropic (class) (class) DREAM.LikelihoodGaussAnisotropic -> TasDREAM::LikelihoodGaussAnisotropic (class) (class) DREAM.Posterior -> TasDREAM::posterior (method) (method) DREAM.PosteriorEmbeddedLikelihood -> TasDREAM::posterior (method-overload) (method) DREAM.genUniformSamples -> TasDREAM::genUniformSamples (method) (method) DREAM.genGaussianSamples -> TasDREAM::genGaussianSamples (method) (method) DREAM.Sample -> TasDREAM::SampleDREAM (method) ``` * Addon module methods and C++ equivalent: ``` Tasmanian.loadNeededValues -> TasGrid::loadNeededValues Tasmanian.reloadLoadedValues -> TasGrid::loadNeededValues Tasmanian.constructAnisotropicSurrogate -> TasGrid::constructSurrogate (anistropic overload) Tasmanian.constructSurplusSurrogate -> TasGrid::constructSurrogate (surplus overload) ``` ### Error Handling The Tasmanian Python module comes with a comprehensive error checking mechanisms where the validity of the inputs to every method are checked and `TasmanianInputError` exception is raised whenever invalid input is encountered. The `TasmanianInputError` class has two variables: * **sVariable** indicates the variable with invalid input or the name of the method if the method was called out of order, e.g., `evaluate()` cannot be called before `loadNeededPoints()` * **sMessage** is a human readable string giving specific description to of the error. ### Acceleration and Thread Safety All acceleration modes are available through the Python interface and the same rules for thread safety apply as in the C++ interface. One point of difference is the `SparseGrid.evaluate()` function, which on the Python side will link to `SparseGrid.evaluateFast()` and therefore not safe to call from different threads. Safe evaluations can be performed with `SparseGrid.evaluateThreadSafe()`. The model callable inputs to load/reload and construct methods will be executed in parallel on most Python implementations. ### Basic Plotting If `matplotlib.pyplot` module is available, `Tasmanian.SparseGrid` will enable two plotting methods: * **plotPoints2D()** plots the nodes associated with the grid * **plotResponse2D()** plots a color image corresponding to the response surface Both methods work only with two dimensional grids. Note that `matplotlib.pyplot` doesn't have to be available during build time, it can be installed later and still used with a current installation of Tasmanian. TASMANIAN-8.1/Doxygen/footer.html000066400000000000000000000013421470551176200165060ustar00rootroot00000000000000 TASMANIAN-8.1/Doxygen/header.html000066400000000000000000000042441470551176200164440ustar00rootroot00000000000000 $projectname: $title $title $treeview $search $mathjax $extrastylesheet
Doxygen $doxygenversion
$projectname  $projectnumber $searchbox
$projectbrief
$projectbrief
TASMANIAN-8.1/Doxygen/tasmanian.css000066400000000000000000000174551470551176200170230ustar00rootroot00000000000000/****************************************************************************** TABLE OF CONTENTS 1 - IMPORTS 2 - GLOBAL 3 - DOXYGEN OVERRIDES ******************************************************************************/ /****************************************************************************** 1 - IMPORTS ******************************************************************************/ @import url('https://fonts.googleapis.com/css?family=Merriweather+Sans|Source+Sans+Pro'); /****************************************************************************** 2 - GLOBAL ******************************************************************************/ html, body { height: 100% !important; } #doc-content { height: calc(100% - 112px); background: #F5F5F5; } html { font-size: 100%; } div.headertitle, div.contents, #main-nav, #projectname { width: 95%; margin: 1em auto; display: block; clear: both; } div.contents { max-width: 60em; text-align: justify; text-justify: inter-word; } #side-nav { background: #F5F5F5; width: 21em; height: calc(100% - 112px); } #nav-tree { background: #F5F5F5; height: 100%; } /****************************************************************************** 3 - DOXYGEN OVERRIDES ******************************************************************************/ body, table, div, p, dl { font-family: 'Source Sans Pro', sans-serif !important; font-size: 1em; } h1, h2, h3, h4, h5, h6 { font-family: 'Merriweather Sans', sans-serif !important; } h2 { font-size: 110%; } /****************************************************************************** 3.1 - PAGE TITLE ******************************************************************************/ #titlearea { border-bottom: none; background: #404040 } #titlearea table { width: 100%; text-align: center; background: url('https://tasmanian.ornl.gov/assets/webtreatsetc-starfield-patterns/JPGS/backgrounsetc-starfield-4.jpg') fixed repeat; } #projectname { font-size: 1.25em; color: #fff; text-shadow: #000 6px 4px 50px; } .doxygen { position: absolute; color: #fff; background: rgba(255, 255, 255, .5); padding: 5px; border-radius: 10px; font-size: .75em; right: 10px; top: 10px; } .doxygen img { width: 60px; } /****************************************************************************** 3.2 - Search ******************************************************************************/ #MSearchField, #MSearchBox .right, #MSearchBox .left { background: #fff; } #MSearchField { font: 1em 'Source Sans Pro', sans-serif !important; border-bottom: 2px solid #000; padding-bottom: .5em; } #MSearchBox { width: 50%; position: relative; background: #fff; margin: 10px auto 0; height: 30px; border-radius: 10px; overflow: hidden; } #MSearchBox .left{ position: relative; top: 5px; } #MSearchBox .left, #MSearchBox .left #MSearchField { width:100% } #MSearchResultsWindow { left: 50% !important; transform: translate(-50%, 4%); } /****************************************************************************** 3.3 - MAIN MENU (TOP) ******************************************************************************/ #main-nav { padding: 0; margin: 0; display: none; } .sm-dox { background-image: none; background-color: #fff; } .sm-dox a, .sm-dox a:focus, .sm-dox a:active, .sm-dox a:hover, .sm-dox a.highlighted { background-image: none; font-size: .85em; } .sm-dox a, .sm-dox a:focus, .sm-dox a:hover, .sm-dox a:active { color: #444; text-shadow: none; } .sm-dox a span.sub-arrow { border-color: #517875 transparent transparent transparent; } .sm-dox a:hover span.sub-arrow { border-color: #517875 transparent transparent transparent; } .sm-dox ul a:hover { background-image: none; background-color: #517875; } #top { border-bottom: 1px solid rgba(126, 88, 38, .75); background: url('https://tasmanian.ornl.gov/assets/webtreatsetc-starfield-patterns/JPGS/backgrounsetc-starfield-4.jpg') fixed repeat; } /****************************************************************************** 3.4 - MAIN MENU (SIDE) ******************************************************************************/ /* div#side-nav { width: 0; } div#side-nav:not([style*="width"]):hover { transition: width .25s; width: 3px; } */ #nav-sync { display: none; } div#nav-tree { background-image: none; } .ui-resizable-handle.ui-resizable-e { border-right: 1px solid rgba(126, 88, 38, .75); background: none; } /****************************************************************************** 3.5 - NAV PATH ******************************************************************************/ div.navpath { display:none } /****************************************************************************** 3.6 - PAGE HEADER ******************************************************************************/ div.header{ background-image: none; background: #dcdcdc; border-bottom: none; margin-bottom: 1em; } div.summary { width: 100%; text-align: center; background: rgba(126, 88, 38, .45); } div.summary a { color: #fff; font-weight: bold; } .headertitle { background-image: none; background: #dcdcdc; max-width: 60em; } .title { font: 2.0em 'Source Sans Pro', sans-serif; } /****************************************************************************** 4 - CONTENT ******************************************************************************/ .PageDoc { position: relative; top: -16px; } /****************************************************************************** 4.1 - GROUP HEADER ******************************************************************************/ h2.groupheader { border-bottom: 1px solid #517875; } /****************************************************************************** 4.2 - MEMBER TABLE ******************************************************************************/ table.memberdecls { width: 100%; } tr.heading h2 { margin-top: .5em; } tr[class^="memitem:"] td { padding: .5em; } tr[class^="memitem:"] td.memTemplItemLeft, tr[class^="memitem:"] td.memItemLeft { background: rgba(126, 88, 38, .45); color: #fff; } tr[class^="memdesc:"] td { padding: .5em; border-bottom: 1px solid rgba(0, 0, 0, .10); } tr[class^="separator:"] { height: 1em; } /****************************************************************************** 4.3 - CODE FRAGMENT ******************************************************************************/ div.fragment { border-radius: 5px; padding: 0.5em; } div.line { font-family: 'Courier New', Courier, monospace !important; font-size: 95%; margin: .5em auto; } /****************************************************************************** 4.4 - MARKDOWN TABLE ******************************************************************************/ table.markdownTable { width: 100%; } /****************************************************************************** 5 - FOOTER ******************************************************************************/ hr.footer { border-color: transparent; } address.footer { margin-top: 1.5em; padding: 3em 0; text-align: center; background: #fff; color: #fff; font-size: 1em; } TASMANIAN-8.1/InterfaceFortran/000077500000000000000000000000001470551176200161415ustar00rootroot00000000000000TASMANIAN-8.1/InterfaceFortran/CMakeLists.txt000066400000000000000000000056101470551176200207030ustar00rootroot00000000000000######################################################################## # Fortran librareis and command line tools ######################################################################## add_library(Tasmanian_libfortran90 TasmanianSG.f90 tsgC2FortranBridge.f90 tsgC2Fortran.cpp) target_include_directories(Tasmanian_libfortran90 PUBLIC $) target_link_libraries(Tasmanian_libfortran90 Tasmanian_addons) set_target_properties(Tasmanian_libfortran90 PROPERTIES OUTPUT_NAME "tasmanianfortran90" SOVERSION ${Tasmanian_VERSION_MAJOR} VERSION ${PROJECT_VERSION}) Tasmanian_rpath_target(TARGET Tasmanian_libfortran90 COMPONENTS SparseGrids DREAM) install(TARGETS Tasmanian_libfortran90 EXPORT "${Tasmanian_export_name}" RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib") ######################################################################## # add the fortran tester and examples executables ######################################################################## add_executable(Tasmanian_fortester fortester.f90) set_target_properties(Tasmanian_fortester PROPERTIES OUTPUT_NAME "fortester" LINKER_LANGUAGE Fortran) Tasmanian_rpath_target(TARGET Tasmanian_fortester USE_CURRENT COMPONENTS SparseGrids DREAM) target_link_libraries(Tasmanian_fortester Tasmanian_libfortran90) ######################################################################## # handle the MPI dependence and MPI tests ######################################################################## if (Tasmanian_ENABLE_MPI) target_link_libraries(Tasmanian_libfortran90 MPI::MPI_Fortran) add_executable(Tasmanian_mpif90 mpitester.f90) set_target_properties(Tasmanian_mpif90 PROPERTIES OUTPUT_NAME "mpitester" LINKER_LANGUAGE Fortran) target_link_libraries(Tasmanian_mpif90 Tasmanian_libfortran90) add_test(MPIFortranGridIO ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/mpitester ${MPIEXEC_POSTFLAGS}) set_tests_properties(MPIFortranGridIO PROPERTIES RUN_SERIAL ON) Tasmanian_set_test_properties(TESTS MPIFortranGridIO) endif() ######################################################################## # Testing ######################################################################## add_test(Fortran90 fortester) Tasmanian_set_test_properties(TESTS Fortran90) ######################################################################## # Installation ######################################################################## install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tasmaniansg.mod" DESTINATION include PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) TASMANIAN-8.1/InterfaceFortran/Examples/000077500000000000000000000000001470551176200177175ustar00rootroot00000000000000TASMANIAN-8.1/InterfaceFortran/Examples/example_sparse_grids.f90000066400000000000000000001051361470551176200244450ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2017, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== PROGRAM TasmanianSGExample USE TasmanianSG IMPLICIT NONE type(TasmanianSparseGrid) :: grid, grid1, grid2, grid3 INTEGER :: dims, outs, level INTEGER :: N1, N2, N3 INTEGER :: N, i, j, verm, vern DOUBLE PRECISION :: err1, err2, err3, err4, exact REAL :: cpuStart, cpuEnd, stages(2,3) INTEGER :: conformal(3) CHARACTER, pointer :: string(:) DOUBLE PRECISION, pointer :: points(:,:), weights(:) DOUBLE PRECISION :: x, y, integ, E DOUBLE PRECISION, allocatable :: transformA(:), transformB(:), values(:,:), tvalues(:,:) DOUBLE PRECISION, allocatable :: res(:), res2(:,:) DOUBLE PRECISION :: desired_x(2) DOUBLE PRECISION :: randPoints(4,1000), randPoints2(2,1000), randPoints3(3,1000) DOUBLE PRECISION :: PI = 4.D0*DATAN(1.D0) ! This is the sound "Glaucodon Ballaratensis" makes :) ! WRITE(*,*) "Ghurrrrrphurrr" ! ============ reference table of rules ============ ! ! 1: clenshaw-curtis 2: clenshaw-curtis-zero ! 3: chebyshev 4: chebyshev-odd ! 5: gauss-legendre 6: gauss-legendreodd ! 7: gauss-patterson 8: leja ! 9: lejaodd 10: rleja ! 11: rleja-odd 12: rleja-double-2 ! 13: rleja-double-4 14: rleja-shifted ! 15: rleja-shifted-even 16: rleja-shifted-double ! 17: max-lebesgue 18: max-lebesgue-odd ! 19: min-lebesgue 20: min-lebesgue-odd ! 21: min-delta 22: min-delta-odd ! 23: gauss-chebyshev-1 24: gauss-chebyshev-1-odd ! 25: gauss-chebyshev-2 26: gauss-chebyshev-2-odd ! 27: fejer2 28: gauss-gegenbauer ! 29: gauss-gegenbauer-odd 30: gauss-jacobi ! 31: gauss-jacobi-odd 32: gauss-laguerre ! 33: gauss-laguerre-odd 34: gauss-hermite ! 35: gauss-hermite-odd 36: custom-tabulated ! 37: localp 38: localp-zero ! 39: semi-localp 40: wavelet ! ============ reference table of grid types ============ ! ! 1: level 2: curved ! 3: iptotal 4: ipcurved ! 5: qptotal 6: qpcurved ! 7: hyperbolic 8: iphyperbolic ! 9: qphyperbolic 10: tensor ! 11: iptensor 12: qptensor ! ============ reference table of refinement types ============ ! ! 1: classic 2: parents first ! 3: directional 4: FDS (both parents and directions) ! ============ reference table of acceleration types ============ ! ! 0: none 1: CPU BLAS 2: GPU cuBLAS ! 3: GPU CUDA 4: GPU MAGMA ! ==================================================================== ! ! EXAMPLE 1: integrate: f(x,y) = exp(-x^2) * cos(y) over [-1,1] x [-1,1] ! using classical Smolyak grid with Clenshaw-Curtis points and weights verm = tsgGetVersionMajor() vern = tsgGetVersionMinor() ! WARNING: do not DEALLOCATE the string pointer, it is const char* string => tsgGetLicense() WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Tasmanian Sparse Grids Fortran Module (TasmanianSG)" WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,"(A,I2,A,I1)") " Tasmanian Sparse Grid module, version: ", verm, ".", vern WRITE(*,"(A,40A)") " license: ", string WRITE(*,*) WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 1: integrate f(x,y) = exp(-x^2) * cos(y), using clenshaw-curtis level nodes" dims = 2 level = 6 ! before you use a grid, you must allocate a new grid call tsgAllocateGrid(grid) CALL tsgMakeGlobalGrid(grid, dims, 0, level, tsg_level, tsg_clenshaw_curtis) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) N = tsgGetNumPoints(grid) integ = 0.0 DO i = 1, N x = points(1, i) y = points(2, i) integ = integ + weights(i) * exp(-x*x) * cos(y) END DO E = abs(integ - 2.513723354063905D+00) WRITE(*,"(A,I4)") " at level: ", level WRITE(*,"(A,I4,A)") " the grid has: ", N, " points" WRITE(*,"(A,E25.16)") " integral: ", integ WRITE(*,"(A,E25.16)") " error: ", E WRITE(*,*) level = 7 ! no need to ask for a new ID when remaking an existing grid CALL tsgMakeGlobalGrid(grid, dims, 0, level, tsg_level, tsg_clenshaw_curtis) ! do not forget to release the memory associated with points and weights DEALLOCATE(points) DEALLOCATE(weights) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) N = tsgGetNumPoints(grid) integ = 0.0 DO i = 1, N x = points(1, i) y = points(2, i) integ = integ + weights(i) * exp(-x*x) * cos(y) END DO E = abs(integ - 2.513723354063905D+00) WRITE(*,"(A,I4)") " at level: ", level WRITE(*,"(A,I4,A)") " the grid has: ", N, " points" WRITE(*,"(A,E25.16)") " integral: ", integ WRITE(*,"(A,E25.16)") " error: ", E WRITE(*,*) DEALLOCATE(points) DEALLOCATE(weights) ! after calling tsgDeallocateGrid(), we can no longer use this grid ! until we call tsgAllocateGrid() again CALL tsgDeallocateGrid(grid) ! ==================================================================== ! ! EXAMPLE 2: integrate: f(x,y) = exp(-x^2) * cos(y) ! over (x,y) in [-5,5] x [-2,3] ! using Gauss-Patterson rules chosen to integrate exactly polynomials of ! total degree up to degree specified by prec WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 2: integrate f(x,y) = exp(-x^2) * cos(y) over [-5,5] x [-2,3] using Gauss-Patterson nodes" dims = 2 level = 20 ALLOCATE(transformA(dims)) ALLOCATE(transformB(dims)) transformA(1) = -5.0 transformA(2) = -2.0 transformB(1) = 5.0 transformB(2) = 3.0 ! need new grid, since we freed this earlier call tsgAllocateGrid(grid) ! gauss-patterson = 7, type_qptotal = 5 CALL tsgMakeGlobalGrid(grid, dims, 0, level, tsg_qptotal, tsg_gauss_patterson) CALL tsgSetDomainTransform(grid, transformA, transformB) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) N = tsgGetNumPoints(grid) integ = 0.0 DO i = 1, N x = points(1, i) y = points(2, i) integ = integ + weights(i) * exp(-x*x) * cos(y) END DO E = abs(integ - 1.861816427518323D+00) WRITE(*,"(A,I4)") " at precision: ", level WRITE(*,"(A,I4,A)") " the grid has: ", N, " points" WRITE(*,"(A,E25.16)") " integral: ", integ WRITE(*,"(A,E25.16)") " error: ", E WRITE(*,*) level = 40 ! no need to ask for a new ID when remaking an existing grid CALL tsgMakeGlobalGrid(grid, dims, 0, level, tsg_qptotal, tsg_gauss_patterson) CALL tsgSetDomainTransform(grid, transformA, transformB) ! do not forget to release the memory associated with points and weights DEALLOCATE(points) DEALLOCATE(weights) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) N = tsgGetNumPoints(grid) integ = 0.0 DO i = 1, N x = points(1, i) y = points(2, i) integ = integ + weights(i) * exp(-x*x) * cos(y) END DO E = abs(integ - 1.861816427518323D+00) WRITE(*,"(A,I4)") " at precision: ", level WRITE(*,"(A,I4,A)") " the grid has: ", N, " points" WRITE(*,"(A,E25.16)") " integral: ", integ WRITE(*,"(A,E25.16)") " error: ", E WRITE(*,*) DEALLOCATE(points) DEALLOCATE(weights) ! keep transformA and transformB for the next example CALL tsgDeallocateGrid(grid) ! ==================================================================== ! ! EXAMPLE 3: integrate: f(x,y) = exp(-x^2) * cos(y) ! over (x,y) in [-5,5] x [-2,3] ! using different rules call tsgAllocateGrid(grid1) call tsgAllocateGrid(grid2) call tsgAllocateGrid(grid3) WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 3: integrate f(x,y) = exp(-x^2) * cos(y) over [-5,5] x [-2,3] using different rules" WRITE(*,*) WRITE(*,*) " Clenshaw-Curtis Gauss-Legendre Gauss-Patterson" WRITE(*,*) " precision points error points error points error" DO level = 9, 30, 4 CALL tsgMakeGlobalGrid(grid1, dims, 0, level, tsg_qptotal, tsg_clenshaw_curtis) CALL tsgSetDomainTransform(grid1, transformA, transformB) CALL tsgMakeGlobalGrid(grid2, dims, 0, level, tsg_qptotal, tsg_gauss_legendre) CALL tsgSetDomainTransform(grid2, transformA, transformB) CALL tsgMakeGlobalGrid(grid3, dims, 0, level, tsg_qptotal, tsg_gauss_patterson) CALL tsgSetDomainTransform(grid3, transformA, transformB) points => tsgGetPoints(grid1) weights => tsgGetQuadratureWeights(grid1) N1 = tsgGetNumPoints(grid1) integ = 0.0 DO i = 1, N1 x = points(1, i) y = points(2, i) integ = integ + weights(i) * exp(-x*x) * cos(y) END DO err1 = abs(integ - 1.861816427518323D+00) DEALLOCATE(points) DEALLOCATE(weights) points => tsgGetPoints(grid2) weights => tsgGetQuadratureWeights(grid2) N2 = tsgGetNumPoints(grid2) integ = 0.0 DO i = 1, N2 x = points(1, i) y = points(2, i) integ = integ + weights(i) * exp(-x*x) * cos(y) END DO err2 = abs(integ - 1.861816427518323D+00) DEALLOCATE(points) DEALLOCATE(weights) points => tsgGetPoints(grid3) weights => tsgGetQuadratureWeights(grid3) N3 = tsgGetNumPoints(grid3) integ = 0.0 DO i = 1, N3 x = points(1, i) y = points(2, i) integ = integ + weights(i) * exp(-x*x) * cos(y) END DO err3 = abs(integ - 1.861816427518323D+00) DEALLOCATE(points) DEALLOCATE(weights) WRITE(*,"(I10,I10,E11.3,I9,E11.3,I9,E11.3)") level, N1, err1, N2, err2, N3, err3 END DO WRITE(*,*) CALL tsgDeallocateGrid(grid1) CALL tsgDeallocateGrid(grid2) CALL tsgDeallocateGrid(grid3) DEALLOCATE(transformA) DEALLOCATE(transformB) ! ==================================================================== ! ! EXAMPLE 4: interpolate: f(x,y) = exp(-x^2) * cos(y) ! with a rule that exactly interpolates polynomials of total degree call tsgAllocateGrid(grid) WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 4: interpolate f(x,y) = exp(-x^2) * cos(y), using clenshaw-curtis iptotal rule" WRITE(*,*) dims = 2 outs = 1 level = 10 desired_x(1) = 0.3 desired_x(2) = 0.7 ! desired value exact = exp(-desired_x(1)**2) * cos(desired_x(2)) CALL tsgMakeGlobalGrid(grid, dims, outs, level, tsg_iptotal, tsg_clenshaw_curtis) N = tsgGetNumNeeded(grid) points => tsgGetNeededPoints(grid) ALLOCATE(values(outs,N)) DO i = 1, N x = points(1, i) y = points(2, i) values(1,i) = exp(-x**2) * cos(y) END DO CALL tsgLoadNeededPoints(grid, values) DEALLOCATE(values) DEALLOCATE(points) ALLOCATE(res(outs)) ! will DEALLOCATE later CALL tsgEvaluate(grid, desired_x, res) E = abs(res(1) - exact) WRITE(*,"(A,I4)") " using polynomials of total degree: ", level WRITE(*,"(A,I4,A)") " the grid has: ", N, " points" WRITE(*,"(A,E25.16)") " interpolant at (0.3,0.7): ", res(1) WRITE(*,"(A,E25.16)") " error: ", E WRITE(*,*) ! do the same with level = 12 level = 12 CALL tsgMakeGlobalGrid(grid, dims, outs, level, tsg_iptotal, tsg_clenshaw_curtis) N = tsgGetNumNeeded(grid) points => tsgGetNeededPoints(grid) ALLOCATE(values(outs,N)) DO i = 1, N x = points(1, i) y = points(2, i) values(1,i) = exp(-x**2) * cos(y) END DO CALL tsgLoadNeededPoints(grid, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluate(grid, desired_x, res) E = abs(res(1) - exact) WRITE(*,"(A,I4)") " using polynomials of total degree: ", level WRITE(*,"(A,I4,A)") " the grid has: ", N, " points" WRITE(*,"(A,E25.16)") " interpolant at (0.3,0.7): ", res(1) WRITE(*,"(A,E25.16)") " error: ", E WRITE(*,*) DEALLOCATE(res) CALL tsgDeallocateGrid(grid) ! prepare random smaples for future tests call random_seed() call random_number(randPoints) ! ==================================================================== ! ! EXAMPLE 5: ! interpolate: f(x1,x2,x3,x4) = exp(-x1^2) * cos(x2) * exp(-x3^2) * cos(x4) ! with Global and Sequence Leja rules ! Skipping example 5: it takes time and slows down testing, but it dosn't show/test any API not covered in other cases ! dims = 4 ! outs = 1 ! level = 15 ! ! CALL cpu_time(cpuStart) ! CALL tsgMakeGlobalGrid(grid, dims, outs, level, tsg_level, tsg_leja) ! CALL cpu_time(cpuEnd) ! stages(1,1) = cpuEnd - cpuStart ! ! N = tsgGetNumPoints(grid) ! ! WRITE(*,*) "-------------------------------------------------------------------------------------------------" ! WRITE(*,*) "Example 5: interpolate f(x1,x2,x3,x4) = exp(-x1^2) * cos(x2) * exp(-x3^2) * cos(x4)" ! WRITE(*,*) " comparign the performance of Global and Sequence grids with leja nodes" ! WRITE(*,"(A,I4)") " using polynomials of total degree up to: ", level ! WRITE(*,"(A,I4,A)") " the grids have: ", N, " points" ! WRITE(*,*) " both grids are evaluated at 1000 random points " ! WRITE(*,*) ! ! points => tsgGetNeededPoints(grid) ! ALLOCATE(values(outs,N)) ! DO i = 1, N ! values(1,i) = exp(-points(1,i)**2) * cos(points(2,i)) * exp(-points(3,i)**2) * cos(points(4,i)) ! END DO ! DEALLOCATE(points) ! ! CALL cpu_time(cpuStart) ! CALL tsgLoadNeededPoints(grid, values) ! CALL cpu_time(cpuEnd) ! stages(1,2) = cpuEnd - cpuStart ! ! ALLOCATE(res2(outs,1000)) ! 2-D result ! ! CALL cpu_time(cpuStart) ! CALL tsgEvaluateBatch(grid, randPoints, 1000, res2) ! CALL cpu_time(cpuEnd) ! stages(1,3) = cpuEnd - cpuStart ! ! CALL cpu_time(cpuStart) ! CALL tsgMakeSequenceGrid(grid, dims, outs, level, tsg_level, tsg_leja) ! CALL cpu_time(cpuEnd) ! stages(2,1) = cpuEnd - cpuStart ! ! ! points are the same, no need to recompue values ! CALL cpu_time(cpuStart) ! CALL tsgLoadNeededPoints(grid, values) ! CALL cpu_time(cpuEnd) ! stages(2,2) = cpuEnd - cpuStart ! ! DEALLOCATE(values) ! ! CALL cpu_time(cpuStart) ! CALL tsgEvaluateBatch(grid, randPoints, 1000, res2) ! CALL cpu_time(cpuEnd) ! stages(2,3) = cpuEnd - cpuStart ! ! WRITE(*,*) "Stage Global Grid Sequence Grid" ! WRITE(*,"(A,E20.8,E20.8)") " make grid ", stages(1,1), stages(2,1) ! WRITE(*,"(A,E20.8,E20.8)") " load needed", stages(1,2), stages(2,2) ! WRITE(*,"(A,E20.8,E20.8)") " evaluate ", stages(1,3), stages(2,3) ! ! CALL tsgDeallocateGrid(grid) ! DEALLOCATE(res2) ! ==================================================================== ! ! EXAMPLE 6: ! interpolate: f(x,y) = exp(-x^2) * cos(y) ! using different refinement schemes ALLOCATE(tvalues(1,1000)) ! true values of f(x,y) DO i = 1, 1000 randPoints2(1,i) = randPoints(1,i) randPoints2(2,i) = randPoints(2,i) tvalues(1,i) = exp(-randPoints(1,i)**2) * cos(randPoints(2,i)) END DO call tsgAllocateGrid(grid1) call tsgAllocateGrid(grid2) call tsgAllocateGrid(grid3) dims = 2 outs = 1 CALL tsgMakeGlobalGrid(grid1, dims, outs, 3, tsg_iptotal, tsg_leja) CALL tsgMakeGlobalGrid(grid2, dims, outs, 3, tsg_iptotal, tsg_leja) CALL tsgMakeGlobalGrid(grid3, dims, outs, 3, tsg_iptotal, tsg_leja) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)**2) * cos(points(2,i)) END DO CALL tsgLoadNeededPoints(grid1, values) CALL tsgLoadNeededPoints(grid2, values) CALL tsgLoadNeededPoints(grid3, values) DEALLOCATE(values) DEALLOCATE(points) WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 6: interpolate: f(x,y) = exp(-x^2) * cos(y)" WRITE(*,*) " using leja nodes and different refinement schemes " WRITE(*,*) " the error is estimated as the maximum from 1000 random points" WRITE(*,*) " Total Degree Curved Surplus" WRITE(*,*) "iteration points error points error points error" ALLOCATE(res2(outs,1000)) ! 2-D result ! iptotal: 3, ipcurved: 4 DO j = 1, 10 CALL tsgSetAnisotropicRefinement(grid1, tsg_iptotal, 10, 1) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)**2) * cos(points(2,i)) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid1, randPoints2, 1000, res2) err1 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err1)then err1 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO CALL tsgSetAnisotropicRefinement(grid2, tsg_ipcurved, 10, 1) N = tsgGetNumNeeded(grid2) points => tsgGetNeededPoints(grid2) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)**2) * cos(points(2,i)) END DO CALL tsgLoadNeededPoints(grid2, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid2, randPoints2, 1000, res2) err2 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err2)then err2 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO CALL tsgSetGlobalSurplusRefinement(grid3, 1.D-10, 1) N = tsgGetNumNeeded(grid3) points => tsgGetNeededPoints(grid3) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)**2) * cos(points(2,i)) END DO CALL tsgLoadNeededPoints(grid3, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid3, randPoints2, 1000, res2) err3 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err3)then err3 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO N1 = tsgGetNumPoints(grid1) N2 = tsgGetNumPoints(grid2) N3 = tsgGetNumPoints(grid3) WRITE(*,"(I9,I9,E12.4,I9,E12.4,I9,E12.4)") j, N1, err1, N2, err2, N3, err3 END DO WRITE(*,*) CALL tsgDeallocateGrid(grid1) CALL tsgDeallocateGrid(grid2) CALL tsgDeallocateGrid(grid3) ! ==================================================================== ! ! EXAMPLE 7: ! interpolate: f(x,y) = exp(-x^2) * cos(y) ! using localp and semilocalp grids WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 7: interpolate: f(x,y) = exp(-x^2) * cos(y)" WRITE(*,*) " using localp and semi-localp rules with depth 7" WRITE(*,*) " the error is estimated as the maximum from 1000 random points" WRITE(*,*) call tsgAllocateGrid(grid1) call tsgAllocateGrid(grid2) dims = 2 outs = 1 CALL tsgMakeLocalPolynomialGrid(grid1, dims, outs, 7, 2, tsg_localp) CALL tsgMakeLocalPolynomialGrid(grid2, dims, outs, 7, 2, tsg_semi_localp) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)**2) * cos(points(2,i)) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid1, randPoints2, 1000, res2) err1 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err1)then err1 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO points => tsgGetNeededPoints(grid2) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)**2) * cos(points(2,i)) END DO CALL tsgLoadNeededPoints(grid2, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid2, randPoints2, 1000, res2) err2 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err2)then err2 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO WRITE(*,"(A,I5)") " Number of points: ", N WRITE(*,"(A,E12.4)") " Error for rule_localp: ", err1 WRITE(*,"(A,E12.4)") " Error for rule_semilocalp: ", err2 WRITE(*,*) " Note: semi-localp wins this competition because the function is very smooth" WRITE(*,*) ! ==================================================================== ! ! EXAMPLE 8: ! interpolate: f(x,y) = cos(0.5 * pi * x) * cos(0.5 * pi * y) ! using localp and semilocalp grids ! remake the true values for the next example DO i = 1, 1000 tvalues(1,i) = cos(0.5 * PI * randPoints2(1,i)) & * cos(0.5 * PI * randPoints2(2,i)) END DO WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 8: interpolate f(x,y) = cos(0.5 * pi * x) * cos(0.5 * pi * y)" WRITE(*,*) " using localp and localp-zero rules with depths 7 and 6" WRITE(*,*) " the error is estimated as the maximum from 1000 random points" WRITE(*,*) dims = 2 outs = 1 CALL tsgMakeLocalPolynomialGrid(grid1, dims, outs, 7, 2, tsg_localp) CALL tsgMakeLocalPolynomialGrid(grid2, dims, outs, 6, 2, tsg_localp_zero) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = cos(0.5 * PI * points(1,i)) & * cos(0.5 * PI * points(2,i)) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid1, randPoints2, 1000, res2) err1 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err1)then err1 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO N = tsgGetNumNeeded(grid2) points => tsgGetNeededPoints(grid2) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = cos(0.5 * PI * points(1,i)) * cos(0.5 * PI * points(2,i)) END DO CALL tsgLoadNeededPoints(grid2, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid2, randPoints2, 1000, res2) err2 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err2)then err2 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO N1 = tsgGetNumPoints(grid1) N2 = tsgGetNumPoints(grid2) WRITE(*,"(A,I5,E12.4)") " For rule_localp Number of points: ", N1, err1 WRITE(*,"(A,I5,E12.4)") " For rule_localp0 Number of points: ", N2, err2 WRITE(*,*) " Note: localp-zero wins this competition because the function is zero at the boundary" WRITE(*,*) ! ==================================================================== ! ! EXAMPLE 9: ! interpolate: f(x,y) = exp(-x) / (1 + 100 * exp(-10 * y)) ! using different refinement schemes ! remake the true values for the next example DO i = 1, 1000 tvalues(1,i) = exp(-randPoints2(1,i)) / (1.0 + 100.0 * exp(-10.0 * randPoints2(2,i))) END DO dims = 2 outs = 1 CALL tsgMakeLocalPolynomialGrid(grid1, dims, outs, 2, -1, tsg_localp) CALL tsgMakeLocalPolynomialGrid(grid2, dims, outs, 2, -1, tsg_localp) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)) / (1.0 + 100.0 * exp(-10.0 * points(2,i))) END DO CALL tsgLoadNeededPoints(grid1, values) CALL tsgLoadNeededPoints(grid2, values) DEALLOCATE(values) DEALLOCATE(points) WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 9: interpolate f(x,y) = exp(-x) / (1 + 100 * exp(-10 * y))" WRITE(*,*) " the error is estimated as the maximum from 1000 random points" WRITE(*,*) " tolerance is set at 1.E-5 and maximal order polynomials are used" WRITE(*,*) WRITE(*,*) " Classic FDS" WRITE(*,*) "iteration points error points error" DO j = 1, 7 ! 1 below corresponds to classic refinement CALL tsgSetLocalSurplusRefinement(grid1, 1.D-5, tsg_classic) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)) / (1.0 + 100.0 * exp(-10.0 * points(2,i))) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid1, randPoints2, 1000, res2) err1 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err1)then err1 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO CALL tsgSetLocalSurplusRefinement(grid2, 1.D-5, tsg_fds) N = tsgGetNumNeeded(grid2) points => tsgGetNeededPoints(grid2) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)) / (1.0 + 100.0 * exp(-10.0 * points(2,i))) END DO CALL tsgLoadNeededPoints(grid2, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid2, randPoints2, 1000, res2) err2 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err2)then err2 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO N1 = tsgGetNumPoints(grid1) N2 = tsgGetNumPoints(grid2) WRITE(*,"(I9,I9,E12.4,I9,E12.4)") j, N1, err1, N2, err2 END DO WRITE(*,*) ! ==================================================================== ! ! EXAMPLE 10: ! interpolate: f(x,y) = exp(-x) / (1 + 100 * exp(-10 * y)) ! using local polynomails and wavelets dims = 2 outs = 1 CALL tsgMakeLocalPolynomialGrid(grid1, dims, outs, 3, 1, tsg_localp) CALL tsgMakeWaveletGrid(grid2, dims, outs, 1, 1) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)) / (1.0 + 100.0 * exp(-10.0 * points(2,i))) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) N = tsgGetNumNeeded(grid2) points => tsgGetNeededPoints(grid2) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)) / (1.0 + 100.0 * exp(-10.0 * points(2,i))) END DO CALL tsgLoadNeededPoints(grid2, values) DEALLOCATE(values) DEALLOCATE(points) WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 10: interpolate f(x,y) = exp(-x) / (1 + 100 * exp(-10 * y))" WRITE(*,*) " the error is estimated as the maximum from 1000 random points" WRITE(*,*) " using local polynomials and wavelets" WRITE(*,*) WRITE(*,*) " Polynomials Wavelets" WRITE(*,*) "iteration points error points error" DO j = 1, 8 CALL tsgSetLocalSurplusRefinement(grid1, 1.D-5, tsg_fds) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)) / (1.0 + 100.0 * exp(-10.0 * points(2,i))) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid1, randPoints2, 1000, res2) err1 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err1)then err1 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO CALL tsgSetLocalSurplusRefinement(grid2, 1.D-5, tsg_fds) N = tsgGetNumNeeded(grid2) points => tsgGetNeededPoints(grid2) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = exp(-points(1,i)) / (1.0 + 100.0 * exp(-10.0 * points(2,i))) END DO CALL tsgLoadNeededPoints(grid2, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid2, randPoints2, 1000, res2) err2 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err2)then err2 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO N1 = tsgGetNumPoints(grid1) N2 = tsgGetNumPoints(grid2) WRITE(*,"(I9,I9,E12.4,I9,E12.4)") j, N1, err1, N2, err2 END DO WRITE(*,*) CALL tsgDeallocateGrid(grid1) CALL tsgDeallocateGrid(grid2) ! ==================================================================== ! ! EXAMPLE 11: interpolate: f(x,y,z) = 1/((1+4x^2)*(1+5y^2)*(1+6z^2)) ! using classical and conformal transformation WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) "Example 11: interpolate f(x,y,z) = 1/((1+4x^2)*(1+5y^2)*(1+6z^2))" WRITE(*,*) " using conformal transformation" WRITE(*,*) " the error is estimated as the maximum from 1000 random points" dims = 3 outs = 1 level = 12 conformal(1) = 4 conformal(2) = 4 conformal(3) = 4 DO i = 1, 1000 randPoints3(1,i) = randPoints(1,i) randPoints3(2,i) = randPoints(2,i) randPoints3(3,i) = randPoints(3,i) tvalues(1,i) = 1.0 / ((1.0 + 4.0 * randPoints3(1,i)**2) * & (1.0 + 5.0 * randPoints3(2,i)**2) * & (1.0 + 6.0 * randPoints3(3,i)**2)) END DO call tsgAllocateGrid(grid1) CALL tsgMakeGlobalGrid(grid1, dims, outs, level, tsg_iptotal, tsg_clenshaw_curtis) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = 1.0 / ((1.0 + 4.0 * points(1,i)**2) * & (1.0 + 5.0 * points(2,i)**2) * & (1.0 + 6.0 * points(3,i)**2)) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid1, randPoints3, 1000, res2) err1 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err1)then err1 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO N1 = tsgGetNumPoints(grid1) CALL tsgMakeGlobalGrid(grid1, dims, outs, level, tsg_iptotal, tsg_clenshaw_curtis) CALL tsgSetConformalTransformASIN(grid1, conformal) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = 1.0 / ((1.0 + 4.0 * points(1,i)**2) * & (1.0 + 5.0 * points(2,i)**2) * & (1.0 + 6.0 * points(3,i)**2)) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid1, randPoints3, 1000, res2) err2 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err2)then err2 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO CALL tsgMakeLocalPolynomialGrid(grid1, dims, outs, level-4, 2, tsg_localp) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = 1.0 / ((1.0 + 4.0 * points(1,i)**2) * & (1.0 + 5.0 * points(2,i)**2) * & (1.0 + 6.0 * points(3,i)**2)) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid1, randPoints3, 1000, res2) err3 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err3)then err3 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO N2 = tsgGetNumPoints(grid1) CALL tsgMakeLocalPolynomialGrid(grid1, dims, outs, level-4, 2, tsg_localp) CALL tsgSetConformalTransformASIN(grid1, conformal) N = tsgGetNumNeeded(grid1) points => tsgGetNeededPoints(grid1) ALLOCATE(values(outs,N)) DO i = 1, N values(1,i) = 1.0 / ((1.0 + 4.0 * points(1,i)**2) * & (1.0 + 5.0 * points(2,i)**2) * & (1.0 + 6.0 * points(3,i)**2)) END DO CALL tsgLoadNeededPoints(grid1, values) DEALLOCATE(values) DEALLOCATE(points) CALL tsgEvaluateBatch(grid1, randPoints3, 1000, res2) err4 = 0.0 DO i = 1, 1000 IF(abs(res2(1,i) - tvalues(1,i)) .GT. err4)then err4 = abs(res2(1,i) - tvalues(1,i)) ENDIF END DO WRITE(*,*) "Grid Type nodes error regular error conformal" WRITE(*,"(A,I8,E18.4,E18.4)") " Global ", N1, err1, err2 WRITE(*,"(A,I8,E18.4,E18.4)") " Localp ", N2, err3, err4 WRITE(*,*) WRITE(*,*) "Note: conformal maps address specific problems with the region of analyticity of a function" WRITE(*,*) " the map can accelerate or slow down convergence depending on the problem" WRITE(*,*) CALL tsgDeallocateGrid(grid1) ! ==================================================================== ! ! cleanup DEALLOCATE(res2) DEALLOCATE(tvalues) WRITE(*,*) "-------------------------------------------------------------------------------------------------" WRITE(*,*) END PROGRAM TasmanianSGExample TASMANIAN-8.1/InterfaceFortran/TasmanianSG.f90000066400000000000000000001012141470551176200206250ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2017, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== Module TasmanianSG implicit none PUBLIC ! default include all symbols, list only exceptions as PRIVATE :: type TasmanianSparseGrid double complex :: pntr end type TasmanianSparseGrid integer, parameter :: tsg_clenshaw_curtis = 1, tsg_clenshaw_curtis_zero = 2, & tsg_chebyshev = 3, tsg_chebyshev_odd = 4, & tsg_gauss_legendre = 5, tsg_gauss_legendreodd = 6, & tsg_gauss_patterson = 7, tsg_leja = 8, & tsg_lejaodd = 9, tsg_rleja = 10, & tsg_rleja_odd = 11, tsg_rleja_double_2 = 12, & tsg_rleja_double_4 = 13, tsg_rleja_shifted = 14, & tsg_rleja_shifted_even = 15, tsg_rleja_shifted_double = 16, & tsg_max_lebesgue = 17, tsg_max_lebesgue_odd = 18, & tsg_min_lebesgue = 19, tsg_min_lebesgue_odd = 20, & tsg_min_delta = 21, tsg_min_delta_odd = 22, & tsg_gauss_chebyshev_1 = 23, tsg_gauss_chebyshev_1_odd = 24, & tsg_gauss_chebyshev_2 = 25, tsg_gauss_chebyshev_2_odd = 26, & tsg_fejer2 = 27, tsg_gauss_gegenbauer = 28, & tsg_gauss_gegenbauer_odd = 29, tsg_gauss_jacobi = 30, & tsg_gauss_jacobi_odd = 31, tsg_gauss_laguerre = 32, & tsg_gauss_laguerre_odd = 33, tsg_gauss_hermite = 34, & tsg_gauss_hermite_odd = 35, tsg_custom_tabulated = 36, & tsg_localp = 37, tsg_localp_zero = 38, & tsg_semi_localp = 39, tsg_wavelet = 40, & tsg_fourier = 41, tsg_localpb = 42, & tsg_level = 1, tsg_curved = 2, & tsg_iptotal = 3, tsg_ipcurved = 4, & tsg_qptotal = 5, tsg_qpcurved = 6, & tsg_hyperbolic = 7, tsg_iphyperbolic = 8, & tsg_qphyperbolic = 9, tsg_tensor = 10, & tsg_iptensor = 11, tsg_qptensor = 12, & tsg_classic = 1, tsg_parents_first = 2, & tsg_directional = 3, tsg_fds = 4, & tsg_stable = 5, & tsg_acc_none = 0, tsg_acc_cpu_blas = 1, tsg_acc_gpu_cublas = 2, & tsg_acc_gpu_rocblas = 2, tsg_acc_gpu_hip = 3, & tsg_acc_gpu_cuda = 3, tsg_acc_gpu_magma = 4 integer :: rows, cols, length double precision, pointer :: matrix(:,:), vector(:) character, pointer :: string(:) PRIVATE :: rows, cols, length, matrix, vector, string contains !======================================================================= subroutine tsgAllocateGrid(grid) type(TasmanianSparseGrid) :: grid call tsgalloc(grid%pntr); end subroutine tsgAllocateGrid subroutine tsgDeallocateGrid(grid) type(TasmanianSparseGrid) :: grid call tsgfree(grid%pntr); end subroutine tsgDeallocateGrid !======================================================================= function tsgIsGlobal(grid) result(res) type(TasmanianSparseGrid) :: grid integer :: flag logical :: res call tsgisg(grid%pntr, flag) if (flag .ne. 0) then res = .true. else res = .false. endif end function !======================================================================= function tsgIsSequence(grid) result(res) type(TasmanianSparseGrid) :: grid integer :: flag logical :: res call tsgiss(grid%pntr, flag) if (flag .ne. 0) then res = .true. else res = .false. endif end function !======================================================================= function tsgIsLocalPolynomial(grid) result(res) type(TasmanianSparseGrid) :: grid integer :: flag logical :: res call tsgisl(grid%pntr, flag) if (flag .ne. 0) then res = .true. else res = .false. endif end function !======================================================================= function tsgIsWavelet(grid) result(res) type(TasmanianSparseGrid) :: grid integer :: flag logical :: res call tsgisw(grid%pntr, flag) if (flag .ne. 0) then res = .true. else res = .false. endif end function !======================================================================= function tsgIsFourier(grid) result(res) type(TasmanianSparseGrid) :: grid integer :: flag logical :: res call tsgisf(grid%pntr, flag) if (flag .ne. 0) then res = .true. else res = .false. endif end function !======================================================================= ! class TasmanianSparseGrid wrapper functions !======================================================================= function tsgGetVersionMajor() result(ver) integer :: ver call tsggvm(ver) end function tsgGetVersionMajor !======================================================================= function tsgGetVersionMinor() result(ver) integer :: ver call tsggvn(ver) end function tsgGetVersionMinor !======================================================================= function tsgGetLicense() result(lic) character, pointer :: lic(:) call tsggli() lic => string end function tsgGetLicense !======================================================================= subroutine tsgMakeGlobalGrid(grid, dims, outs, depth, gtype, rule, & aweights, alpha, beta, customRuleFilename, levelLimits) type(TasmanianSparseGrid) :: grid integer, intent(in) :: dims, outs, depth, gtype, rule integer, optional, target :: aweights(:), levelLimits(dims) double precision, optional :: alpha, beta character(len=*), optional :: customRuleFilename integer :: opt_flags(5) character(len=80) :: cfn = char(0) double precision :: al, be integer, pointer :: aw(:) => null() integer, pointer :: ll(:) => null() opt_flags = 0 if ( present(aweights) ) then opt_flags(1) = 1 aw => aweights endif if ( present(alpha) ) then opt_flags(2) = 1 al = alpha endif if ( present(beta) ) then opt_flags(3) = 1 be = beta endif if ( present(customRuleFilename) ) then opt_flags(4) = 1 cfn = customRuleFilename//char(0) endif if ( present(levelLimits) ) then opt_flags(5) = 1 ll => levelLimits endif call tsgmg(grid%pntr, dims, outs, depth, gtype, rule, opt_flags, aw, al, be, cfn, ll) end subroutine tsgMakeGlobalGrid !======================================================================= subroutine tsgMakeSequenceGrid(grid, dims, outs, depth, gtype, rule, aweights, levelLimits) type(TasmanianSparseGrid) :: grid integer :: dims, outs, depth, gtype, rule integer, optional, target :: aweights(:), levelLimits(dims) integer :: opt_flags(2) integer, pointer :: aw(:) => null() integer, pointer :: ll(:) => null() opt_flags = 0 if ( present(aweights) ) then opt_flags(1) = 1 aw => aweights endif if ( present(levelLimits) ) then opt_flags(2) = 1 ll => levelLimits endif call tsgms(grid%pntr, dims, outs, depth, gtype, rule, opt_flags, aw, ll) end subroutine tsgMakeSequenceGrid !======================================================================= subroutine tsgMakeLocalPolynomialGrid(grid, dims, outs, depth, order, rule, levelLimits) type(TasmanianSparseGrid) :: grid integer :: dims, outs, depth integer, optional :: order, rule integer, optional, target :: levelLimits(dims) integer :: opt_flags(3), or, ru integer, pointer :: ll(:) => null() opt_flags = 0 if ( present(order) ) then opt_flags(1) = 1 or = order endif if ( present(rule) ) then opt_flags(2) = 1 ru = rule endif if ( present(levelLimits) ) then opt_flags(3) = 1 ll => levelLimits endif call tsgml(grid%pntr, dims, outs, depth, opt_flags, or, ru, ll) end subroutine tsgMakeLocalPolynomialGrid !======================================================================= subroutine tsgMakeWaveletGrid(grid, dims, outs, depth, order, levelLimits) type(TasmanianSparseGrid) :: grid integer :: dims, outs, depth integer, optional, target :: levelLimits(dims) integer, optional :: order integer :: opt_flags(2), or integer, pointer :: ll(:) => null() opt_flags = 0 if ( present(order) ) then opt_flags(1) = 1 or = order endif if ( present(levelLimits) ) then opt_flags(2) = 1 ll => levelLimits endif call tsgmw(grid%pntr, dims, outs, depth, opt_flags, or, ll) end subroutine tsgMakeWaveletGrid !======================================================================= subroutine tsgMakeFourierGrid(grid, dims, outs, depth, gtype, aweights, levelLimits) type(TasmanianSparseGrid) :: grid integer :: dims, outs, depth, gtype integer, optional, target :: aweights(:), levelLimits(dims) integer :: opt_flags(2) integer, pointer :: aw(:) => null() integer, pointer :: ll(:) => null() opt_flags = 0 if ( present(aweights) ) then opt_flags(1) = 1 aw => aweights endif if ( present(levelLimits) ) then opt_flags(2) = 1 ll => levelLimits endif call tsgmf(grid%pntr, dims, outs, depth, gtype, opt_flags, aw, ll) end subroutine tsgMakeFourierGrid !======================================================================= subroutine tsgCopyGrid(grid, source) type(TasmanianSparseGrid) :: grid, source call tsgcp(grid%pntr, source) end subroutine tsgCopyGrid !======================================================================= subroutine tsgUpdateGlobalGrid(grid, depth, gtype, aweights) type(TasmanianSparseGrid) :: grid integer, intent(in) :: depth, gtype integer, optional, target :: aweights(:) integer :: opt_flags = 0 integer, pointer :: aw(:) => null() if ( present(aweights) ) then opt_flags = 1 aw => aweights endif call tsgug(grid%pntr, depth, gtype, opt_flags, aw) end subroutine tsgUpdateGlobalGrid !======================================================================= subroutine tsgUpdateSequenceGrid(grid, depth, gtype, aweights) type(TasmanianSparseGrid) :: grid integer, intent(in) :: depth, gtype integer, optional, target :: aweights(:) integer :: opt_flags = 0 integer, pointer :: aw(:) => null() if ( present(aweights) ) then opt_flags = 1 aw => aweights endif call tsgus(grid%pntr, depth, gtype, opt_flags, aw) end subroutine tsgUpdateSequenceGrid !======================================================================= function tsgRead(grid, filename) result(res) type(TasmanianSparseGrid) :: grid character(len=*), intent(in) :: filename logical :: res integer :: N, i, flag character, allocatable :: cfilename(:) N = len(trim(filename)) allocate(cfilename(N+1)) do i = 1, N cfilename(i) = filename(i:i) end do cfilename(N+1) = CHAR(0) call tsgrea(grid%pntr, cfilename, flag) res = (flag .ne. 0) deallocate(cfilename) end function tsgRead !======================================================================= subroutine tsgWrite(grid, filename, useBinary) type(TasmanianSparseGrid) :: grid logical, intent(in), optional :: useBinary integer :: ubin character(len=*), intent(in) :: filename integer :: N, i character, allocatable :: cfilename(:) N = len(trim(filename)) allocate(cfilename(N+1)) do i = 1, N cfilename(i) = filename(i:i) end do cfilename(N+1) = CHAR(0) if(present(useBinary))then if(useBinary)then ubin = 1 else ubin = 0 endif else ubin = 1 endif call tsgwri(grid%pntr, cfilename, ubin) deallocate(cfilename) end subroutine tsgWrite !======================================================================= function tsgGetAlpha(grid) result(alpha) type(TasmanianSparseGrid) :: grid double precision :: alpha call tsggal(grid%pntr, alpha) end function tsgGetAlpha !======================================================================= function tsgGetBeta(grid) result(beta) type(TasmanianSparseGrid) :: grid double precision :: beta call tsggbe(grid%pntr, beta) end function tsgGetBeta !======================================================================= function tsgGetOrder(grid) result(order) type(TasmanianSparseGrid) :: grid integer :: order call tsggor(grid%pntr, order) end function tsgGetOrder !======================================================================= function tsgGetNumDimensions(grid) result(dims) type(TasmanianSparseGrid) :: grid integer :: dims call tsggnd(grid%pntr, dims) end function tsgGetNumDimensions !======================================================================= function tsgGetNumOutputs(grid) result(outs) type(TasmanianSparseGrid) :: grid integer :: outs call tsggno(grid%pntr, outs) end function tsgGetNumOutputs !======================================================================= function tsgGetRule(grid) result(rule) type(TasmanianSparseGrid) :: grid integer :: rule call tsggru(grid%pntr, rule) end function tsgGetRule !======================================================================= function tsgGetNumLoaded(grid) result(num) type(TasmanianSparseGrid) :: grid integer :: num call tsggnl(grid%pntr, num) end function tsgGetNumLoaded !======================================================================= function tsgGetNumNeeded(grid) result(num) type(TasmanianSparseGrid) :: grid integer :: num call tsggnn(grid%pntr, num) end function tsgGetNumNeeded !======================================================================= function tsgGetNumPoints(grid) result(num) type(TasmanianSparseGrid) :: grid integer :: num call tsggnp(grid%pntr, num) end function tsgGetNumPoints !======================================================================= function tsgGetLoadedPoints(grid) result(p) type(TasmanianSparseGrid) :: grid double precision, pointer :: p(:,:) integer :: rows, cols rows = tsgGetNumDimensions(grid) cols = tsgGetNumLoaded(grid) allocate(p(rows,cols)) call tsgglp(grid%pntr, p) end function tsgGetLoadedPoints !======================================================================= function tsgGetNeededPoints(grid) result(p) type(TasmanianSparseGrid) :: grid double precision, pointer :: p(:,:) integer :: rows, cols rows = tsgGetNumDimensions(grid) cols = tsgGetNumNeeded(grid) allocate(p(rows,cols)) call tsggdp(grid%pntr, p) end function tsgGetNeededPoints !======================================================================= function tsgGetPoints(grid) result(p) type(TasmanianSparseGrid) :: grid double precision, pointer :: p(:,:) integer :: rows, cols rows = tsgGetNumDimensions(grid) cols = tsgGetNumPoints(grid) allocate(p(rows,cols)) call tsggpp(grid%pntr, p) end function tsgGetPoints !======================================================================= subroutine tsgGetLoadedPointsStatic(grid, points) type(TasmanianSparseGrid) :: grid double precision :: points(:,:) call tsgglp(grid%pntr, points) end subroutine tsgGetLoadedPointsStatic !======================================================================= subroutine tsgGetNeededPointsStatic(grid, points) type(TasmanianSparseGrid) :: grid double precision :: points(:,:) call tsggdp(grid%pntr, points) end subroutine tsgGetNeededPointsStatic !======================================================================= subroutine tsgGetPointsStatic(grid, points) type(TasmanianSparseGrid) :: grid double precision :: points(:,:) call tsggpp(grid%pntr, points) end subroutine tsgGetPointsStatic !======================================================================= function tsgGetQuadratureWeights(grid) result(w) type(TasmanianSparseGrid) :: grid integer :: length double precision, pointer :: w(:) length = tsgGetNumPoints(grid) allocate(w(length)) call tsggqw(grid%pntr, w) end function tsgGetQuadratureWeights !======================================================================= subroutine tsgGetQuadratureWeightsStatic(grid, weights) type(TasmanianSparseGrid) :: grid double precision :: weights(*) call tsggqw(grid%pntr, weights) end subroutine tsgGetQuadratureWeightsStatic !======================================================================= function tsgGetInterpolationWeights(grid, x) result(w) type(TasmanianSparseGrid) :: grid integer :: length double precision :: x(*) double precision, pointer :: w(:) length = tsgGetNumPoints(grid) allocate(w(length)) call tsggiw(grid%pntr, x, w) end function tsgGetInterpolationWeights !======================================================================= subroutine tsgGetInterpolationWeightsStatic(grid, x, weights) type(TasmanianSparseGrid) :: grid double precision :: x(:) double precision :: weights(:) call tsggiw(grid%pntr, x, weights) end subroutine tsgGetInterpolationWeightsStatic !======================================================================= subroutine tsgLoadNeededPoints(grid, values) type(TasmanianSparseGrid) :: grid double precision :: values(:,:) call tsglnp(grid%pntr, values) end subroutine tsgLoadNeededPoints !======================================================================= subroutine tsgEvaluate(grid, x, y) type(TasmanianSparseGrid) :: grid double precision, intent(in) :: x(:) double precision :: y(:) call tsgeva(grid%pntr, x, y) end subroutine tsgEvaluate !======================================================================= subroutine tsgEvaluateFast(grid, x, y) type(TasmanianSparseGrid) :: grid double precision, intent(in) :: x(:) double precision :: y(:) call tsgevf(grid%pntr, x, y) end subroutine tsgEvaluateFast !======================================================================= subroutine tsgEvaluateBatch(grid, x, numX, y) type(TasmanianSparseGrid) :: grid integer :: numX double precision :: x(:,:), y(:,:) call tsgevb(grid%pntr, x, numX, y) end subroutine tsgEvaluateBatch !======================================================================= subroutine tsgEvaluateHierarchicalFunctions(grid, x, numX, y) type(TasmanianSparseGrid) :: grid integer :: numX double precision :: x(:,:), y(:,:) if ( .not. tsgIsFourier(grid) ) then call tsgehf(grid%pntr, x, numX, y) else write(*,*) "ERROR: called tsgEvaluateHierarchicalFunctions() on a Fourier grid, " write(*,*) " use tsgEvaluateComplexHierarchicalFunctions() instead" endif end subroutine tsgEvaluateHierarchicalFunctions !======================================================================= subroutine tsgEvaluateComplexHierarchicalFunctions(grid, x, numX, y) type(TasmanianSparseGrid) :: grid integer :: numX double precision :: x(:,:) double complex :: y(:,:) double precision, allocatable :: y_c_style(:) integer :: i, j if ( tsgIsFourier(grid) ) then allocate(y_c_style(2*size(y,1)*size(y,2))) call tsgehf(grid%pntr, x, numX, y_c_style) do j = 1,size(y,2) do i = 1,size(y,1) y(i,j) = cmplx( y_c_style( 2*size(y,1)*(j-1) + 2*i-1 ), y_c_style( 2*size(y,1)*(j-1) + 2*i), kind(y) ) enddo enddo else write(*,*) "ERROR: called tsgEvaluateComplexHierarchicalFunctions() on a non-Fourier grid, " write(*,*) " use tsgEvaluateHierarchicalFunctions() instead" endif end subroutine tsgEvaluateComplexHierarchicalFunctions !======================================================================= subroutine tsgEvaluateSparseHierarchicalFunctions(grid, x, numX, pntr, indx, y) type(TasmanianSparseGrid) :: grid integer :: numX double precision :: x(:,:) integer, pointer :: pntr(:), indx(:) double precision, pointer :: y(:) integer :: numNZ if ( .not. tsgIsFourier(grid) ) then call tsgehz(grid%pntr, x, numX, numNZ) allocate( pntr(numX+1), indx(numNZ), y(numNZ) ) call tsgehs(grid%pntr, x, numX, pntr, indx, y) else write(*,*) "ERROR: called tsgEvaluateSparseHierarchicalFunctions() on a Fourier grid" endif end subroutine tsgEvaluateSparseHierarchicalFunctions !======================================================================= function tsgGetHierarchicalCoefficients(grid) result(c) type(TasmanianSparseGrid) :: grid double precision, pointer :: c(:) if ( .not. tsgIsFourier(grid) ) then allocate(c(tsgGetNumOutputs(grid)*tsgGetNumPoints(grid))) call tsgghc(grid%pntr, c) else write(*,*) "ERROR: called tsgGetHierarchicalCoefficients() on a Fourier grid, " write(*,*) " use tsgGetComplexHierarchicalCoefficients() instead" endif end function tsgGetHierarchicalCoefficients !======================================================================= subroutine tsgGetHierarchicalCoefficientsStatic(grid, c) type(TasmanianSparseGrid) :: grid double precision :: c(:) if ( .not. tsgIsFourier(grid) ) then call tsgghc(grid%pntr, c) else write(*,*) "ERROR: called tsgGetHierarchicalCoefficientsStatic() on a Fourier grid, " write(*,*) " use tsgGetComplexHierarchicalCoefficientsStatic() instead" endif end subroutine tsgGetHierarchicalCoefficientsStatic !======================================================================= function tsgGetComplexHierarchicalCoefficients(grid) result(c) type(TasmanianSparseGrid) :: grid double complex, pointer :: c(:) double precision, allocatable :: c_real(:) integer :: i if ( tsgIsFourier(grid) ) then allocate(c(tsgGetNumOutputs(grid)*tsgGetNumPoints(grid))) allocate(c_real(2*tsgGetNumOutputs(grid)*tsgGetNumPoints(grid))) call tsgghc(grid%pntr, c_real) do i = 1,size(c) c(i) = cmplx( c_real(i), c_real(i + size(c)), kind(c) ) enddo deallocate(c_real) else write(*,*) "ERROR: called tsgGetComplexHierarchicalCoefficients() on a non-Fourier grid, " write(*,*) " use tsgGetHierarchicalCoefficients() instead" endif end function tsgGetComplexHierarchicalCoefficients !======================================================================= subroutine tsgGetComplexHierarchicalCoefficientsStatic(grid, c) type(TasmanianSparseGrid) :: grid double complex :: c(:) double precision :: c_real(2*size(c)) integer :: i if ( tsgIsFourier(grid) ) then call tsgghc(grid%pntr, c_real) do i = 1,size(c) c(i) = cmplx( c_real(i), c_real(i + size(c)), kind(c) ) enddo else write(*,*) "ERROR: called tsgGetComplexHierarchicalCoefficientsStatic() on a non-Fourier grid, " write(*,*) " use tsgGetHierarchicalCoefficientsStatic() instead" endif end subroutine tsgGetComplexHierarchicalCoefficientsStatic !======================================================================= subroutine tsgSetHierarchicalCoefficients(grid,c) type(TasmanianSparseGrid) :: grid double precision :: c(:) call tsgshc(grid%pntr, c) end subroutine tsgSetHierarchicalCoefficients !======================================================================= function tsgGetHierarchicalSupport(grid) result(c) type(TasmanianSparseGrid) :: grid double precision, pointer :: c(:,:) allocate(c(tsgGetNumDimensions(grid), tsgGetNumPoints(grid))) call tsghsu(grid%pntr, c) end function tsgGetHierarchicalSupport !======================================================================= subroutine tsgIntegrate(grid, q) type(TasmanianSparseGrid) :: grid double precision :: q(:) call tsgint(grid%pntr, q) end subroutine tsgIntegrate !======================================================================= subroutine tsgSetDomainTransform(grid, transformA, transformB) type(TasmanianSparseGrid) :: grid double precision :: transformA(*), transformB(*) call tsgsdt(grid%pntr, transformA, transformB) end subroutine tsgSetDomainTransform !======================================================================= function tsgIsSetDomainTransform(grid) result(res) type(TasmanianSparseGrid) :: grid logical :: res call tsgidt(grid%pntr, res) end function tsgIsSetDomainTransform !======================================================================= subroutine tsgClearDomainTransform(grid) type(TasmanianSparseGrid) :: grid call tsgcdt(grid%pntr) end subroutine tsgClearDomainTransform !======================================================================= subroutine tsgGetDomainTransform(grid, transformA, transformB) type(TasmanianSparseGrid) :: grid double precision :: transformA(*), transformB(*) call tsggdt(grid%pntr, transformA, transformB) end subroutine tsgGetDomainTransform !======================================================================= subroutine tsgSetAnisotropicRefinement(grid, gtype, minGrowth, output, levelLimits) type(TasmanianSparseGrid) :: grid integer :: gtype, minGrowth, output integer, optional, target :: levelLimits(:) integer :: opt_flags = 0 integer, pointer :: ll(:) => null() if (present(levelLimits)) then opt_flags = 1 ll => levelLimits endif call tsgsar(grid%pntr, gtype, minGrowth, output-1, opt_flags, ll) end subroutine tsgSetAnisotropicRefinement !======================================================================= function tsgEstimateAnisotropicCoefficients(grid, gtype, output) result(coeff) type(TasmanianSparseGrid) :: grid integer :: gtype, output, N integer, pointer :: coeff(:) N = tsgGetNumDimensions(grid) if ((gtype .EQ. tsg_curved) .OR. (gtype .EQ. tsg_ipcurved) .OR. (gtype .EQ. tsg_qpcurved))then N = N * 2 endif allocate(coeff(N)) call tsgeac(grid%pntr, gtype, output-1, coeff) end function tsgEstimateAnisotropicCoefficients !======================================================================= subroutine tsgSetGlobalSurplusRefinement(grid, tolerance, output, levelLimits) type(TasmanianSparseGrid) :: grid integer :: output integer, optional, target :: levelLimits(:) double precision :: tolerance integer :: opt_flags = 0 integer, pointer :: ll(:) => null() if (present(levelLimits)) then opt_flags = 1 ll => levelLimits endif call tsgssr(grid%pntr, tolerance, output-1, opt_flags, ll) end subroutine tsgSetGlobalSurplusRefinement !======================================================================= subroutine tsgSetLocalSurplusRefinement(grid, tolerance, rtype, output, levelLimits) type(TasmanianSparseGrid) :: grid integer :: rtype integer, optional :: output integer, optional, target :: levelLimits(:) double precision :: tolerance integer :: opt_flags(2), theout integer, pointer :: ll(:) => null() opt_flags = 0 if (present(output)) then opt_flags(1) = 1 theout = output-1 endif if (present(levelLimits)) then opt_flags(2) = 1 ll => levelLimits endif call tsgshr(grid%pntr, tolerance, rtype, opt_flags, theout, ll) end subroutine tsgSetLocalSurplusRefinement !======================================================================= subroutine tsgClearRefinement(grid) type(TasmanianSparseGrid) :: grid call tsgcre(grid%pntr) end subroutine tsgClearRefinement !======================================================================= subroutine tsgMergeRefinement(grid) type(TasmanianSparseGrid) :: grid call tsgmre(grid%pntr) end subroutine tsgMergeRefinement !======================================================================= subroutine tsgSetConformalTransformASIN(grid, truncate) type(TasmanianSparseGrid) :: grid integer :: truncate(:) call tsgsca(grid%pntr, truncate) end subroutine tsgSetConformalTransformASIN !======================================================================= function tsgIsSetConformalTransformASIN(grid) result(isset) type(TasmanianSparseGrid) :: grid integer :: res logical :: isset call tsgica(grid%pntr, res) if (res .EQ. 0)then isset = .FALSE. else isset = .TRUE. endif end function tsgIsSetConformalTransformASIN !======================================================================= subroutine tsgClearConformalTransform(grid) type(TasmanianSparseGrid) :: grid call tsgcct(grid%pntr) end subroutine tsgClearConformalTransform !======================================================================= function tsgGetConformalTransformASIN(grid) result(truncate) type(TasmanianSparseGrid) :: grid integer :: N integer, allocatable :: truncate(:) N = tsgGetNumDimensions(grid) allocate(truncate(N)) call tsggca(grid%pntr, truncate) end function tsgGetConformalTransformASIN !======================================================================= subroutine tsgPrintStats(grid) type(TasmanianSparseGrid) :: grid call tsgpri(grid%pntr) end subroutine tsgPrintStats !======================================================================= ! Addon/MPI methods ! !======================================================================= subroutine tsgMPIGridSend(grid, destination, tag, comm, ierr) type(TasmanianSparseGrid) :: grid integer :: destination, tag, comm, ierr call tsgmpigsend(grid, destination, tag, comm, ierr) end subroutine tsgMPIGridSend subroutine tsgMPIGridRecv(grid, source, tag, comm, stats, ierr) type(TasmanianSparseGrid) :: grid integer :: source, tag, comm, stats(:), ierr call tsgmpigrecv(grid, source, tag, comm, ierr) end subroutine tsgMPIGridRecv subroutine tsgMPIGridBcast(grid, root, comm, ierr) type(TasmanianSparseGrid) :: grid integer :: root, comm, ierr call tsgmpigcast(grid, root, comm, ierr) end subroutine tsgMPIGridBcast !======================================================================= ! do NOT call THOSE FUNCTIONS DIRECTLY ! !======================================================================= subroutine tsgReceiveString(l, S) integer :: l character, target :: S(l) length = l string => S(1:length) end subroutine tsgReceiveString !======================================================================= subroutine tsgReceiveVector(s, V) integer :: s double precision, target :: V(s) length = s vector => V(1:length) end subroutine tsgReceiveVector !======================================================================= subroutine tsgReceiveMatrix(r, c, M) integer :: r, c double precision, target :: M(r,c) rows = r cols = c matrix => M(1:rows,1:cols) end subroutine tsgReceiveMatrix !======================================================================= end MODULE TASMANIAN-8.1/InterfaceFortran/fortester.f90000066400000000000000000001672171470551176200205140ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== program FORTESTER USE TasmanianSG implicit none integer, parameter :: seed = 86456 double precision, parameter :: pi = 4.0D+0 * atan(1.0D+0) character, pointer :: licence(:) character(14), parameter :: filename = 'fortranio.test' type(TasmanianSparseGrid) :: grid, grid_II double precision, pointer :: rnd(:,:) double precision, pointer :: points(:,:), weights(:), pointsb(:,:), weightsb(:) integer :: i_a, i_b, i_c, i_d, i, j double precision :: d_a, d_b, d_c, d_d, int, int2 logical :: bool integer, allocatable :: int_1d_a(:), int_1d_b(:), int_1d_c(:), int_1d_d(:) double precision, allocatable :: double_1d_a(:), double_1d_b(:), double_1d_c(:), double_1d_d(:) double complex, allocatable :: dcmplx_1d_a(:), dcmplx_1d_b(:), dcmplx_1d_c(:), dcmplx_1d_d(:) integer, allocatable :: int_2d_a(:,:), int_2d_b(:,:), int_2d_c(:,:), int_2d_d(:,:) double precision, allocatable :: double_2d_a(:,:), double_2d_b(:,:), double_2d_c(:,:), double_2d_d(:,:) double complex, allocatable :: dcmplx_2d_a(:,:), dcmplx_2d_b(:,:), dcmplx_2d_c(:,:), dcmplx_2d_d(:,:) integer, pointer :: int_pnt_1d_a(:), int_pnt_1d_b(:), int_pnt_1d_c(:) double precision, pointer :: double_pnt_1d_a(:), double_pnt_1d_b(:), double_pnt_1d_c(:) double complex, pointer :: dcmplx_pnt_1d_a(:), dcmplx_pnt_1d_b(:), dcmplx_pnt_1d_c(:) write(*,'(a)') 'Testing TASMANIAN FORTRAN interface' write(*,*) ! read library meta-data licence => tsgGetLicense() write(*,"(A,I2,A,I1)") "Tasmanian Sparse Grid module: ", tsgGetVersionMajor(), ".", tsgGetVersionMinor() write(*,"(A,40A)") "Licence: ", licence ! initialize random number generator call srand(seed) call tsgAllocateGrid(grid) call tsgAllocateGrid(grid_II) !======================================================================= ! tsgIs***() !======================================================================= ! test type of grid call tsgMakeGlobalGrid(grid, 2, 0, 1, tsg_level, tsg_clenshaw_curtis) if ( (.not. tsgIsGlobal(grid)) .or. tsgIsSequence(grid) .or. tsgIsLocalPolynomial(grid) & .or. tsgIsFourier(grid) .or. tsgIsWavelet(grid) ) then write(*,*) "Mismatch in tsgIsGlobal" stop 1 endif call tsgMakeSequenceGrid(grid, 2, 1, 3, tsg_level, tsg_min_lebesgue) if ( .not. tsgIsSequence(grid) ) then write(*,*) "Mismatch in tsgIsSequence" stop 1 endif call tsgMakeLocalPolynomialGrid(grid, 3, 1, 2, 2, tsg_localp) if ( (.not. tsgIsLocalPolynomial(grid)) .or. tsgIsSequence(grid) .or. tsgIsGlobal(grid) & .or. tsgIsFourier(grid) .or. tsgIsWavelet(grid) ) then write(*,*) "Mismatch in tsgIsLocalPolynomial" stop 1 endif call tsgMakeWaveletGrid(grid, 3, 1, 2, 1) if ( .not. tsgIsWavelet(grid) ) then write(*,*) "Mismatch in tsgIsWavelet" stop 1 endif call tsgMakeFourierGrid(grid, 3, 1, 1, tsg_level) if ( .not. tsgIsFourier(grid) ) then write(*,*) "Mismatch in tsgIsFourier" stop 1 endif ! test transform if ( tsgIsSetDomainTransform(grid) ) then write(*,*) "Mismatch in tsgIsSetDomainTransform" stop 1 endif call tsgMakeGlobalGrid(grid, 3, 0, 2, tsg_level, tsg_clenshaw_curtis) call tsgSetDomainTransform(grid, transformA=(/ 3.0d0, -7.0d0, -12.0d0 /), transformB=(/ 5.0d0, -6.0d0, 17.0d0 /)) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( .not. tsgIsSetDomainTransform(grid) ) then write(*,*) "Mismatch in tsgIsSetDomainTransform" stop 1 endif deallocate(points, weights) !======================================================================= ! tsgMakeGlobalGrid() !======================================================================= ! Check for correct points and weights allocate( pointsb(2,5), weightsb(5) ) pointsb = reshape((/0.0D+0, 0.0D+0, 0.0D+0, -1.0D+0, 0.0D+0, 1.0D+0, -1.0D+0, 0.0D+0, 1.0D+0, 0.0D+0/), shape(pointsb)) weightsb = reshape((/4.0D+0/3.0D+0, 2.0D+0/3.0D+0, 2.0D+0/3.0D+0, 2.0D+0/3.0D+0, 2.0D+0/3.0D+0/), shape(weightsb)) call tsgMakeGlobalGrid(grid, 2, 0, 1, tsg_level, tsg_clenshaw_curtis) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( norm(pointsb-points,size(points)) > 1.d-11 .OR. norm1d(weightsb-weights) > 1.d-11 ) then write(*,*) "Mismatch in tsgMakeGlobal: core case 1", sum(abs(pointsb-points)), sum(abs(weightsb-weights)) stop 1 end if deallocate( pointsb, weightsb, points, weights ) call tsgMakeGlobalGrid(grid, 2, 0, 2, tsg_level, tsg_clenshaw_curtis) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ((abs(points(2, 4) + sqrt(0.5D+0)) > 1.0D-11) .OR. & (abs(points(2, 5) - sqrt(0.5D+0)) > 1.0D-11) .OR. & (abs(weights(7) - 1.0D+0/9.0D+0) > 1.0D-11))then write(*,*) "Mismatch in tsgMakeGlobal: core case 2", & abs(points(2, 4) - sqrt(0.5D+0)), abs(points(2, 5) - sqrt(0.5D+0)), abs(weights(7) - 1.0D+0/9.0D+0) stop 1 end if deallocate(points, weights) call tsgMakeGlobalGrid(grid, 3, 0, 4, tsg_level, tsg_fejer2) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( (abs(sum(points)) > 1.0D-11) .OR. (abs(sum(weights)-8.0D+0) > 1.0D-11) )then write(*,*) "Mismatch in tsgMakeGlobal: core case 3" write(*,*) abs(sum(points)), abs(sum(weights) - 8.0D+0) stop 1 end if deallocate(points, weights) allocate( pointsb(1,4), weightsb(4) ) pointsb(1,:) = (/0.0D+0, 1.0D+0, -1.0D+0, sqrt(1.0D+0/3.0D+0)/) weightsb = (/4.0D+0/3.0D+0, 1.0D+0/3.0D+0, 1.0D+0/3.0D+0, 0.0D+0/) call tsgMakeGlobalGrid(grid, 1, 0, 3, tsg_level, tsg_leja) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( (norm2d(pointsb-points) > 1.0D-11) .OR. (norm1d(weightsb-weights) > 1.0D-11) )then write(*,*) "Mismatch in tsgMakeGlobal: core case 4", norm2d(pointsb-points), norm1d(weightsb-weights) stop 1 end if deallocate(pointsb, weightsb, points, weights) ! test transform call tsgMakeGlobalGrid(grid, 3, 0, 2, tsg_level, tsg_clenshaw_curtis) call tsgSetDomainTransform(grid, transformA=(/ 3.0d0, -7.0d0, -12.0d0 /), transformB=(/ 5.0d0, -6.0d0, 17.0d0 /)) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( (abs(sum(weights)-58.d0) > 1.d-11) .or. & (abs(maxval(points(1,:))-5.d0) > 1.d-11) .or. (abs(minval(points(1,:))-3.d0) > 1.d-11) .or. & (abs(maxval(points(2,:))+6.d0) > 1.d-11) .or. (abs(minval(points(2,:))+7.d0) > 1.d-11) .or. & (abs(maxval(points(3,:))-17.d0) > 1.d-11) .or. (abs(minval(points(3,:))+12.d0) > 1.d-11) ) then write(*,*) "Mismatch in tsgMakeGlobal: transform " stop 1 endif deallocate(points, weights) ! test alpha/beta call tsgMakeGlobalGrid(grid, 1, 0, 4, tsg_level, tsg_gauss_hermite, alpha=2.0D+0) weights => tsgGetQuadratureWeights(grid) if ( (abs(sum(weights)-0.5d0*sqrt(pi)) > 1.D-11) .OR. (abs(tsgGetBeta(grid)) > 1.D-11) & .OR. (abs(tsgGetAlpha(grid) - 2.0D+0) > 1.D-11) .OR. (tsgGetOrder(grid) /= -1)) then write(*,*) "Mismatch in tsgMakeGlobal: alpha/beta", sum(weights), tsgGetBeta(grid) stop 1 endif deallocate(weights) ! test anisotropy allocate( pointsb(2,4) ) pointsb = reshape((/0.0D+0, 0.0D+0, 0.0D+0, 1.0D+0, 0.0D+0, -1.0D+0, 1.0D+0, 0.0D+0/), shape(pointsb)) call tsgMakeGlobalGrid(grid, 2, 0, 2, tsg_level, tsg_leja, aweights=(/2,1/)) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( (norm2d(pointsb-points) > 1.D-11) .OR. (abs(sum(weights)-4.0D+0) > 1.D-11))then write(*,*) "Mismatch in tsgMakeGlobal: anisotropy", norm2d(pointsb-points), sum(weights) stop 1 endif deallocate(pointsb, points, weights) ! make custom rule file open(unit=17,iostat=i,file='tasmanianFortranTestCustomRule.table',status='replace') if (i .ne. 0) then print*, "Cannot open file with custom rule" stop 1 endif write(17,*) "description: test Gauss-Legendre" write(17,*) "levels: 5" write(17,*) "1 1 2 3 3 5 4 7 5 9" do i = 0,4 call tsgMakeGlobalGrid(grid, 1, 0, i, tsg_level, tsg_gauss_legendre) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) do j = 1,tsgGetNumPoints(grid) write(17,*) weights(j), points(1,j) enddo deallocate(points,weights) enddo close(unit=17) ! test custom rule call tsgMakeGlobalGrid(grid, 2, 0, 4, tsg_level, tsg_custom_tabulated, & customRuleFilename="tasmanianFortranTestCustomRule.table") call tsgMakeGlobalGrid(grid_II, 2, 0, 4, tsg_level, tsg_gauss_legendre) points => tsgGetPoints(grid) pointsb => tsgGetPoints(grid_II) weights => tsgGetQuadratureWeights(grid) weightsb => tsgGetQuadratureWeights(grid_II) if ( (norm1d(weights-weightsb) > 1.d-11) .or. (norm2d(points-pointsb) > 1.d-11) ) then write(*,*) "Mismatch in tsgMakeGlobal: custom rule" endif deallocate(points,pointsb,weights,weightsb) ! delete custom rule file open(unit=17,file='tasmanianFortranTestCustomRule.table',status='replace') close(unit=17,status='delete') ! test conformal do i = 7,8 call tsgMakeGlobalGrid(grid, 2, 0, i, tsg_qptotal, tsg_gauss_patterson) call tsgMakeGlobalGrid(grid_II, 2, 0, i, tsg_qptotal, tsg_gauss_patterson) call tsgSetConformalTransformASIN(grid_II, (/4,4/)) points => tsgGetPoints(grid) pointsb => tsgGetPoints(grid_II) weights => tsgGetQuadratureWeights(grid) weightsb => tsgGetQuadratureWeights(grid_II) int = sum( weights * ( 1.d0/((1.d0+5.d0*points(1,:)**2)*(1.d0+5.d0*points(2,:)**2 )) ) ) int2 = sum( weightsb * ( 1.d0/((1.d0+5.d0*pointsb(1,:)**2)*(1.d0+5.d0*pointsb(2,:)**2)) ) ) deallocate(points, pointsb, weights, weightsb) if ( abs(int-1.028825601981092d0**2) < abs(int2 - 1.028825601981092d0**2) ) then write(*,*) "Mismatch in tsgMakeGlobal: conformal map" stop 1 endif enddo ! test level limits call tsgMakeGlobalGrid(grid, 2, 0, 20, tsg_qptotal, tsg_clenshaw_curtis, (/1,1/), 0.0D+0, 0.0D+0, levelLimits=(/1,3/)) call tsgMakeGlobalGrid(grid_II, 2, 0, 1, tsg_tensor, tsg_clenshaw_curtis, (/1,3/)) points => tsgGetPoints(grid) pointsb => tsgGetPoints(grid_II) weights => tsgGetQuadratureWeights(grid) weightsb => tsgGetQuadratureWeights(grid_II) if ( (tsgGetNumPoints(grid_II) .ne. tsgGetNumPoints(grid)) .or. & (norm2d(points-pointsb) > 1.0D-11) .or. (norm1d(weights-weightsb) > 1.0D-11) ) then write(*,*) "Mismatch in tsgMakeGlobal: level limits", tsgGetNumPoints(grid_II), norm2d(points-pointsb) stop 1 end if deallocate(points, pointsb, weights, weightsb) !======================================================================= ! tsgCopyGrid() !======================================================================= call tsgMakeGlobalGrid(grid, 2, 1, 3, tsg_iptotal, tsg_clenshaw_curtis) call tsgSetConformalTransformASIN(grid, (/4,4/)) points => tsgGetPoints(grid) call tsgCopyGrid(grid_II,grid) call tsgDeallocateGrid(grid) pointsb => tsgGetPoints(grid_II) if ( norm2d(points-pointsb) > 1.0D-11 ) then write(*,*) "Mismatch in tsgMakeGlobal: copy grid" stop 1 end if call tsgAllocateGrid(grid) deallocate(points, pointsb) !======================================================================= ! tsgRead/Write() !======================================================================= call tsgMakeFourierGrid(grid, 3, 1, 3, tsg_level, (/1, 2, 3/)) points => tsgGetPoints(grid) call tsgWrite(grid, filename) call tsgDeallocateGrid(grid) call tsgAllocateGrid(grid) ! reset the grid if (.not. tsgRead(grid, filename)) then write(*,*) "File read failed: 1" stop 1 end if pointsb => tsgGetPoints(grid) if ( norm2d(points-pointsb) > 1.0D-11 ) then write(*,*) "Mismatch in tsgMakeGlobal: read/write 1" stop 1 end if deallocate(pointsb) call tsgWrite(grid, filename, .false.) call tsgDeallocateGrid(grid) call tsgAllocateGrid(grid) ! reset the grid if (.not. tsgRead(grid, filename)) then write(*,*) "File read failed: 2" stop 1 end if pointsb => tsgGetPoints(grid) if ( norm2d(points-pointsb) > 1.0D-11 ) then write(*,*) "Mismatch in tsgMakeGlobal: read/write 2" stop 1 end if deallocate(points, pointsb) call tsgWrite(grid, filename, .true.) call tsgDeallocateGrid(grid) call tsgAllocateGrid(grid) ! reset the grid if (.not. tsgRead(grid, filename)) then write(*,*) "File read failed: 3" stop 1 end if if ( tsgGetRule(grid) /= tsg_fourier ) then write(*,*) "Mismatch in tsgMakeGlobal: read/write 3" stop 1 end if if (tsgRead(grid, 'nonafile')) then write(*,*) "File read failed: 4" stop 1 end if !======================================================================= ! tsgMakeSequenceGrid() !======================================================================= call tsgMakeSequenceGrid(grid, 2, 1, 3, tsg_level, tsg_min_lebesgue) points => tsgGetPoints(grid) allocate(pointsb(2,10)) pointsb = reshape((/ 0.D0, 0.D0, 0.D0, 1.D0, 0.D0, -1.D0, 0.D0, sqrt(1.D0/3.D0), 1.D0, 0.D0, & 1.D0, 1.D0, 1.D0, -1.D0, -1.D0, 0.D0, -1.D0, 1.D0, sqrt(1.D0/3.D0), 0.D0 /), shape(pointsb)) if ( norm2d(points-pointsb) > 1.0D-11 ) then write(*,*) "Mismatch in tsgMakeSequenceGrid: core case 1" stop 1 endif deallocate(points, pointsb) ! test transform call tsgMakeSequenceGrid(grid, 3, 1, 2, tsg_level, tsg_rleja) call tsgSetDomainTransform(grid, transformA=(/3.0d0,-7.0d0,-12.0d0/), transformB=(/5.0d0,-6.0d0,17.0d0/)) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( (abs(sum(weights)-58.d0) > 1.d-11) .or. & (abs(maxval(points(1,:))-5.d0) > 1.d-11) .or. (abs(minval(points(1,:))-3.d0) > 1.d-11) .or. & (abs(maxval(points(2,:))+6.d0) > 1.d-11) .or. (abs(minval(points(2,:))+7.d0) > 1.d-11) .or. & (abs(maxval(points(3,:))-17.d0) > 1.d-11) .or. (abs(minval(points(3,:))+12.d0) > 1.d-11) ) then write(*,*) "Mismatch in tsgMakeSequenceGrid: transform " stop 1 endif allocate( double_1d_a(tsgGetNumPoints(grid)) ) call tsgGetQuadratureWeightsStatic(grid, double_1d_a) if ( (abs(sum(weights)-58.d0) > 1.d-11) ) then write(*,*) "Mismatch in tsgGetQuadratureWeightsStatic" stop 1 endif deallocate( double_1d_a ) allocate(double_1d_a(3), double_1d_b(3)) call tsgGetDomainTransform(grid, double_1d_a, double_1d_b) if ( (norm1d(double_1d_a - (/ 3.0d0, -7.0d0, -12.0d0 /)) > 1.d-11) .or. & (norm1d(double_1d_b - (/ 5.0d0, -6.0d0, 17.0d0 /)) > 1.d-11) ) then write(*,*) "Mismatch in tsgGetDomainTransform " stop 1 endif deallocate(points, weights, double_1d_a, double_1d_b) call tsgClearDomainTransform(grid) points => tsgGetPoints(grid) if ( tsgIsSetDomainTransform(grid) .or. & (abs(maxval(points(1,:))-1.d0) > 1.d-11) .or. (abs(minval(points(1,:))+1.d0) > 1.d-11) .or. & (abs(maxval(points(2,:))-1.d0) > 1.d-11) .or. (abs(minval(points(2,:))+1.d0) > 1.d-11) .or. & (abs(maxval(points(3,:))-1.d0) > 1.d-11) .or. (abs(minval(points(3,:))+1.d0) > 1.d-11) ) then write(*,*) "Mismatch in tsgMakeSequenceGrid: cleared transform " stop 1 endif deallocate(points) ! test anisotropy allocate(pointsb(2,4)) pointsb = reshape((/0.0D+0, 0.0D+0, 0.0D+0, 1.0D+0, 0.0D+0, -1.0D+0, 1.0D+0, 0.0D+0/), shape(pointsb)) call tsgMakeSequenceGrid(grid, 2, 1, 2, tsg_level, tsg_leja, aweights=(/2,1/)) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( (norm2d(pointsb-points) > 1.D-11) .or. (abs(sum(weights)-4.0D+0) > 1.D-11) ) then write(*,*) "Mismatch in tsgMakeSequenceGrid: anisotropy", norm2d(pointsb-points), sum(weights) stop 1 endif deallocate(pointsb, points, weights) ! test conformal allocate( pointsb(2,100), double_2d_a(1,100), double_2d_b(1,100), double_2d_c(1,100) ) rnd => random(2,100) pointsb = -1.d0 + 2.d0 * rnd double_2d_a(1,:) = 1.d0/((1.d0+5.d0*pointsb(1,:)**2)*(1.d0+5.d0*pointsb(2,:)**2)) do i = 7,8 call tsgMakeSequenceGrid(grid, 2, 1, i, tsg_iptotal, tsg_rleja) points => tsgGetPoints(grid) allocate(double_2d_d(1, tsgGetNumPoints(grid))) double_2d_d(1,:) = 1.d0/((1.d0+5.d0*points(1,:)**2)*(1.d0+5.d0*points(2,:)**2)) call tsgLoadNeededPoints(grid, double_2d_d) call tsgEvaluateBatch(grid,pointsb,100,double_2d_b) deallocate(points, double_2d_d) call tsgMakeSequenceGrid(grid_II, 2, 1, i, tsg_iptotal, tsg_rleja) call tsgSetConformalTransformASIN(grid_II, (/4,4/)) points => tsgGetPoints(grid_II) allocate(double_2d_d(1, tsgGetNumPoints(grid_II))) double_2d_d(1,:) = 1.d0/((1.d0+5.d0*points(1,:)**2)*(1.d0+5.d0*points(2,:)**2)) call tsgLoadNeededPoints(grid_II, double_2d_d) call tsgEvaluateBatch(grid_II,pointsb,100,double_2d_c) deallocate(points, double_2d_d) if ( norm2d(double_2d_a-double_2d_b) < norm2d(double_2d_a-double_2d_c) ) then write(*,*) "Mismatch in tsgMakeSequenceGrid: conformal map" stop 1 endif enddo deallocate(rnd, pointsb, double_2d_a, double_2d_b, double_2d_c) ! test level limits call tsgMakeSequenceGrid(grid, 2, 1, 20, tsg_iptotal, tsg_min_delta, levelLimits=(/1,3/)) call tsgMakeSequenceGrid(grid_II, 2, 1, 1, tsg_tensor, tsg_min_delta, aweights=(/1,3/)) points => tsgGetPoints(grid) pointsb => tsgGetPoints(grid_II) weights => tsgGetQuadratureWeights(grid) weightsb => tsgGetQuadratureWeights(grid_II) if ( (tsgGetNumPoints(grid_II) .ne. tsgGetNumPoints(grid)) .or. & (norm2d(points-pointsb) > 1.0D-11) .or. (norm1d(weights-weightsb) > 1.0D-11) ) then write(*,*) "Mismatch in tsgMakeSequenceGrid: level limits", tsgGetNumPoints(grid_II), norm2d(points-pointsb) stop 1 end if deallocate(points, pointsb, weights, weightsb) !======================================================================= ! tsgMakeLocalPolynomialGrid() !======================================================================= ! test transform call tsgMakeLocalPolynomialGrid(grid, 3, 1, 2, 2, tsg_localp) call tsgSetDomainTransform(grid, transformA=(/3.0d0,-7.0d0,-12.0d0/), transformB=(/5.0d0,-6.0d0,17.0d0/)) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( (abs(sum(weights)-58.d0) > 1.d-11) .or. & (abs(maxval(points(1,:))-5.d0) > 1.d-11) .or. (abs(minval(points(1,:))-3.d0) > 1.d-11) .or. & (abs(maxval(points(2,:))+6.d0) > 1.d-11) .or. (abs(minval(points(2,:))+7.d0) > 1.d-11) .or. & (abs(maxval(points(3,:))-17.d0) > 1.d-11) .or. (abs(minval(points(3,:))+12.d0) > 1.d-11) ) then write(*,*) "Mismatch in tsgMakeLocalPolynomialGrid: transform " stop 1 endif deallocate(points, weights) ! test conformal allocate( pointsb(2,100), double_2d_a(1,100), double_2d_b(1,100), double_2d_c(1,100) ) rnd => random(2,100) pointsb = -1.d0 + 2.d0 * rnd double_2d_a(1,:) = 1.d0/((1.d0+5.d0*pointsb(1,:)**2)*(1.d0+5.d0*pointsb(2,:)**2)) do i = 3,4 call tsgMakeLocalPolynomialGrid(grid, 2, 1, i, 2, tsg_semi_localp) points => tsgGetPoints(grid) allocate(double_2d_d(1, tsgGetNumPoints(grid))) double_2d_d(1,:) = 1.d0/((1.d0+5.d0*points(1,:)**2)*(1.d0+5.d0*points(2,:)**2)) call tsgLoadNeededPoints(grid, double_2d_d) call tsgEvaluateBatch(grid,pointsb,100,double_2d_b) deallocate(points, double_2d_d) call tsgMakeLocalPolynomialGrid(grid_II, 2, 1, i, 2, tsg_semi_localp) call tsgSetConformalTransformASIN(grid_II, (/4,4/)) points => tsgGetPoints(grid_II) allocate(double_2d_d(1, tsgGetNumPoints(grid_II))) double_2d_d(1,:) = 1.d0/((1.d0+5.d0*points(1,:)**2)*(1.d0+5.d0*points(2,:)**2)) call tsgLoadNeededPoints(grid_II, double_2d_d) call tsgEvaluateBatch(grid_II,pointsb,100,double_2d_c) deallocate(points, double_2d_d) if ( norm2d(double_2d_a-double_2d_b) < norm2d(double_2d_a-double_2d_c) ) then write(*,*) "Mismatch in tsgMakeSequenceGrid: conformal map" stop 1 endif enddo deallocate(rnd, pointsb, double_2d_a, double_2d_b, double_2d_c) ! test level limits call tsgMakeLocalPolynomialGrid(grid, 3, 1, 3, 2, tsg_semi_localp, levelLimits=(/1,2,3/)) points => tsgGetPoints(grid) if ( minval(abs(points(1,:)-0.5)) < 1.e-8 ) then write(*,*) "Mismatch in tsgMakeLocalPolynomialGrid: level limits, dim 1" stop 1 endif if ( minval(abs(points(2,:)-0.75)) < 1.e-8 ) then write(*,*) "Mismatch in tsgMakeLocalPolynomialGrid: level limits, dim 2" stop 1 endif if ( minval(abs(points(3,:)-0.125)) < 1.e-8 ) then write(*,*) "Mismatch in tsgMakeLocalPolynomialGrid: level limits, dim 3" stop 1 endif deallocate(points) !======================================================================= ! tsgMakeWaveletGrid() !======================================================================= ! test transform call tsgMakeWaveletGrid(grid, 3, 1, 2, 1) call tsgSetDomainTransform(grid, transformA=(/3.0d0,-7.0d0,-12.0d0/), transformB=(/5.0d0,-6.0d0,17.0d0/)) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( (abs(sum(weights)-58.d0) > 1.d-11) .or. & (abs(maxval(points(1,:))-5.d0) > 1.d-11) .or. (abs(minval(points(1,:))-3.d0) > 1.d-11) .or. & (abs(maxval(points(2,:))+6.d0) > 1.d-11) .or. (abs(minval(points(2,:))+7.d0) > 1.d-11) .or. & (abs(maxval(points(3,:))-17.d0) > 1.d-11) .or. (abs(minval(points(3,:))+12.d0) > 1.d-11) ) then write(*,*) "Mismatch in tsgMakeWaveletGrid: transform " stop 1 endif deallocate(points, weights) ! correctness of 1-D call tsgMakeWaveletGrid(grid, 1, 1, 2, 1) call tsgMakeLocalPolynomialGrid(grid_II, 1, 1, 3, 1, tsg_localp) points => tsgGetPoints(grid) pointsb => tsgGetPoints(grid_II) if ( norm2d(points-pointsb) > 1.d-11 ) then write(*,*) "Mismatch in tsgMakeWaveletGrid: points " stop 1 endif deallocate(points, pointsb) ! test conformal do i = 3,4 call tsgMakeWaveletGrid(grid, 2, 1, i, 1) call tsgMakeWaveletGrid(grid_II, 2, 1, i, 1) call tsgSetConformalTransformASIN(grid_II, (/4,4/)) points => tsgGetPoints(grid) pointsb => tsgGetPoints(grid_II) weights => tsgGetQuadratureWeights(grid) weightsb => tsgGetQuadratureWeights(grid_II) int = sum( weights * ( 1.d0/((1.d0+5.d0*points(1,:)**2)*(1.d0+5.d0*points(2,:)**2)) ) ) int2 = sum( weightsb * ( 1.d0/((1.d0+5.d0*pointsb(1,:)**2)*(1.d0+5.d0*pointsb(2,:)**2)) ) ) if ( abs(int-1.028825601981092d0**2) < abs(int2 - 1.028825601981092d0**2) ) then write(*,*) "Mismatch in tsgMakeWaveletGrid: conformal map" stop 1 endif deallocate(points, pointsb, weights, weightsb) enddo ! test level limits call tsgMakeWaveletGrid(grid, 3, 1, 2, 1, levelLimits=(/0,1,2/)) points => tsgGetPoints(grid) if ( minval(abs(points(1,:)-0.5)) < 1.e-8 ) then write(*,*) "Mismatch in tsgMakeWaveletGrid: level limits, dim 1" stop 1 endif if ( minval(abs(points(2,:)-0.75)) < 1.e-8 ) then write(*,*) "Mismatch in tsgMakeWaveletGrid: level limits, dim 2" stop 1 endif if ( minval(abs(points(3,:)-0.125)) < 1.e-8 ) then write(*,*) "Mismatch in tsgMakeWaveletGrid: level limits, dim 3" stop 1 endif deallocate(points) !======================================================================= ! tsgMakeFourierGrid() !======================================================================= ! test transform call tsgMakeFourierGrid(grid, 3, 1, 1, tsg_level) call tsgSetDomainTransform(grid, transformA=(/3.0d0,-7.0d0,-12.0d0/), transformB=(/5.0d0,-6.0d0,17.0d0/)) points => tsgGetPoints(grid) weights => tsgGetQuadratureWeights(grid) if ( (abs(sum(weights)-58.d0) > 1.d-11) .or. & (abs(maxval(points(1,:))-13./3.d0) > 1.d-11) .or. (abs(minval(points(1,:))-3.d0) > 1.d-11) .or. & (abs(maxval(points(2,:))+19./3.d0) > 1.d-11) .or. (abs(minval(points(2,:))+7.d0) > 1.d-11) .or. & (abs(maxval(points(3,:))-22./3.d0) > 1.d-11) .or. (abs(minval(points(3,:))+12.d0) > 1.d-11) ) then write(*,*) "Mismatch in tsgMakeFourierGrid: transform " stop 1 endif deallocate(points, weights) ! correctness of 1-D call tsgMakeFourierGrid(grid, 1, 1, 2, tsg_level) allocate(pointsb(1,9)) pointsb = reshape( (/ 0.d0, 1.0/3.d0, 2.0/3.d0, 1.0/9.d0, 2.0/9.d0, & 4.0/9.d0, 5.0/9.d0, 7.0/9.d0, 8.0/9.d0 /), (/1, 9/) ) points => tsgGetPoints(grid) if ( norm2d(points-pointsb) > 1.d-11 ) then write(*,*) "Mismatch in tsgMakeFourierGrid: points " stop 1 endif deallocate(points, pointsb) ! test level limits call tsgMakeFourierGrid(grid, 3, 1, 3, tsg_level, levelLimits=(/0,1,2/)) points => tsgGetPoints(grid) if ( maxval(abs(points(1,:))) > 1.e-8 ) then write(*,*) "Mismatch in tsgMakeFourierGrid: level limits, dim 1" stop 1 endif if ( minval(abs(points(2,:)-1./9.d0)) < 1.e-8 ) then write(*,*) "Mismatch in tsgMakeFourierGrid: level limits, dim 2" stop 1 endif if ( minval(abs(points(3,:)-1./27.d0)) < 1.e-8 ) then write(*,*) "Mismatch in tsgMakeFourierGrid: level limits, dim 3" stop 1 endif deallocate(points) write(*,*) "tsgMake* functions: PASS" !======================================================================= ! tsgGet***Points() !======================================================================= allocate(pointsb(2,5)) pointsb = reshape( (/ 0.d0, 0.d0, 0.d0, -1.d0, 0.d0, & 1.d0, -1.d0, 0.d0, 1.d0, 0.d0 /), (/ 2, 5 /) ) call tsgMakeGlobalGrid(grid, 2, 1, 1, tsg_level, tsg_clenshaw_curtis) points => tsgGetPoints(grid) if ( norm2d(points-pointsb) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetPoints: core case 1" stop 1 endif deallocate(points) points => tsgGetNeededPoints(grid) if ( norm2d(points-pointsb) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetNeededPoints: core case 1" stop 1 endif deallocate(points) allocate(points(tsgGetNumDimensions(grid),tsgGetNumPoints(grid))) call tsgGetPointsStatic(grid, points ) if ( norm2d(points-pointsb) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetPointsStatic: core case 1" stop 1 endif deallocate(points) allocate(points(tsgGetNumDimensions(grid),tsgGetNumPoints(grid))) call tsgGetNeededPointsStatic(grid, points ) if ( norm2d(points-pointsb) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetNeededPointsStatic: core case 1" stop 1 endif deallocate(points, pointsb) !======================================================================= ! tsgLoadNeededPoints(), tsgGetLoadedPoints() !======================================================================= call tsgMakeGlobalGrid(grid, 2, 2, 4, tsg_level, tsg_min_delta) points => tsgGetPoints(grid) pointsb => tsgGetNeededPoints(grid) if ( norm2d(points-pointsb) > 1.d-11 ) then write(*,*) "Mismatch in tsgLoadNeededPoints: tsgGetNeededPoints" stop 1 endif deallocate(pointsb) allocate(double_2d_a(2,tsgGetNumPoints(grid))) double_2d_a(1,:) = exp( -points(1,:)**2 - points(2,:)**2 ) double_2d_a(2,:) = cos( -points(1,:) - 2.d0 * points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) pointsb => tsgGetLoadedPoints(grid) if ( norm2d(points-pointsb) > 1.d-11 ) then write(*,*) "Mismatch in tsgLoadNeededPoints: tsgGetLoadedPoints" stop 1 endif deallocate(pointsb) allocate(pointsb(tsgGetNumDimensions(grid),tsgGetNumPoints(grid))) call tsgGetLoadedPointsStatic(grid, pointsb) if ( norm2d(points-pointsb) > 1.d-11 ) then write(*,*) "Mismatch in tsgLoadNeededPoints: tsgGetLoadedPointsStatic" stop 1 endif if ( tsgGetNumNeeded(grid) .ne. 0 ) then write(*,*) "Mismatch in tsgLoadNeededPoints: tsgGetNumNeeded" stop 1 endif deallocate(points, pointsb, double_2d_a) !======================================================================= ! tsgEvaluate(), tsgEvaluateBatch() !======================================================================= allocate(double_2d_a(4,2), double_2d_c(4,2), double_1d_a(4), double_1d_b(4), pointsb(2,2)) pointsb = reshape( (/ 1./3.d0, 1./3.d0, pi/6.d0, -sqrt(2.d0)/2.d0 /), shape(pointsb) ) double_2d_a(1,:) = 0.3d0 double_2d_a(2,:) = pointsb(1,:) + pointsb(2,:) double_2d_a(3,:) = pointsb(1,:)**2 + pointsb(2,:)**2 + pointsb(1,:)*pointsb(2,:) double_2d_a(4,:) = pointsb(1,:)**3 + pointsb(2,:)**3 + pointsb(1,:)*(pointsb(2,:)**2) call tsgMakeLocalPolynomialGrid(grid, 2, 4, 1, 1, tsg_localp) points => tsgGetPoints(grid) allocate(double_2d_b(4,tsgGetNumPoints(grid))) double_2d_b(1,:) = 0.3d0 double_2d_b(2,:) = points(1,:) + points(2,:) double_2d_b(3,:) = points(1,:)**2 + points(2,:)**2 + points(1,:)*points(2,:) double_2d_b(4,:) = points(1,:)**3 + points(2,:)**3 + points(1,:)*(points(2,:)**2) call tsgLoadNeededPoints(grid, double_2d_b) call tsgEvaluate(grid,reshape(pointsb(:,1),(/2/)),double_1d_a) call tsgEvaluateFast(grid,reshape(pointsb(:,2),(/2/)),double_1d_b) call tsgEvaluateBatch(grid,pointsb,2,double_2d_c) do i=1,2 if ( ( norm1d(double_2d_a(i,:)-double_2d_c(i,:)) > 1.d-11 ) .or. & ( abs(double_2d_a(i,1)-double_1d_a(i)) + abs(double_2d_a(i,2)-double_1d_b(i)) ) > 1.d-11 ) then write(*,*) "Mismatch in tsgEvaluateBatch: case 1, output ", i stop 1 endif enddo do i=3,4 if ( ( norm1d(double_2d_a(i,:)-double_2d_c(i,:)) < 1.d-8 ) .or. & ( abs(double_2d_a(i,1)-double_1d_a(i)) + abs(double_2d_a(i,2)-double_1d_b(i)) ) < 1.d-8 ) then write(*,*) "Mismatch in tsgEvaluateBatch: case 1, output ", i stop 1 endif enddo deallocate(double_2d_a, double_2d_b, double_2d_c, double_1d_a, double_1d_b, pointsb, points) allocate(double_2d_a(4,2), double_2d_c(4,2), double_1d_a(4), double_1d_b(4), pointsb(2,2)) pointsb = reshape( (/ 1./3.d0, 1./3.d0, pi/6.d0, -sqrt(2.d0)/2.d0 /), shape(pointsb) ) double_2d_a(1,:) = 0.3d0 double_2d_a(2,:) = pointsb(1,:) + pointsb(2,:) double_2d_a(3,:) = pointsb(1,:)**2 + pointsb(2,:)**2 + pointsb(1,:)*pointsb(2,:) double_2d_a(4,:) = pointsb(1,:)**3 + pointsb(2,:)**3 + pointsb(1,:)*(pointsb(2,:)**2) call tsgMakeLocalPolynomialGrid(grid, 2, 4, 1, 2, tsg_localp) points => tsgGetPoints(grid) allocate(double_2d_b(4,tsgGetNumPoints(grid))) double_2d_b(1,:) = 0.3d0 double_2d_b(2,:) = points(1,:) + points(2,:) double_2d_b(3,:) = points(1,:)**2 + points(2,:)**2 + points(1,:)*points(2,:) double_2d_b(4,:) = points(1,:)**3 + points(2,:)**3 + points(1,:)*(points(2,:)**2) call tsgLoadNeededPoints(grid, double_2d_b) call tsgEvaluate(grid,reshape(pointsb(:,1),(/2/)),double_1d_a) call tsgEvaluate(grid,reshape(pointsb(:,2),(/2/)),double_1d_b) call tsgEvaluateBatch(grid,pointsb,2,double_2d_c) do i=1,2 if ( norm1d(double_2d_a(i,:)-double_2d_c(i,:)) > 1.d-11 .or. & ( abs(double_2d_a(i,1)-double_1d_a(i)) + abs(double_2d_a(i,2)-double_1d_b(i)) ) > 1.d-11 ) then write(*,*) "Mismatch in tsgEvaluateBatch: case 2, output ", i stop 1 endif enddo do i=3,4 if ( ( norm1d(double_2d_a(i,:)-double_2d_c(i,:)) < 1.d-8 ) .or. & ( abs(double_2d_a(i,1)-double_1d_a(i)) + abs(double_2d_a(i,2)-double_1d_b(i)) ) < 1.d-8 ) then write(*,*) "Mismatch in tsgEvaluateBatch: case 2, output ", i stop 1 endif enddo deallocate(double_2d_a, double_2d_b, double_2d_c, double_1d_a, double_1d_b, pointsb, points) allocate(double_2d_a(4,2), double_2d_c(4,2), double_1d_a(4), double_1d_b(4), pointsb(2,2)) pointsb = reshape( (/ 1./3.d0, 1./3.d0, pi/6.d0, -sqrt(2.d0)/2.d0 /), shape(pointsb) ) double_2d_a(1,:) = 0.3d0 double_2d_a(2,:) = pointsb(1,:) + pointsb(2,:) double_2d_a(3,:) = pointsb(1,:)**2 + pointsb(2,:)**2 double_2d_a(4,:) = pointsb(1,:)**3 + pointsb(2,:)**3 + pointsb(1,:)*(pointsb(2,:)**2) call tsgMakeLocalPolynomialGrid(grid, 2, 4, 1, 2, tsg_semi_localp) points => tsgGetPoints(grid) allocate(double_2d_b(4,tsgGetNumPoints(grid))) double_2d_b(1,:) = 0.3d0 double_2d_b(2,:) = points(1,:) + points(2,:) double_2d_b(3,:) = points(1,:)**2 + points(2,:)**2 double_2d_b(4,:) = points(1,:)**3 + points(2,:)**3 + points(1,:)*(points(2,:)**2) call tsgLoadNeededPoints(grid, double_2d_b) call tsgEvaluate(grid,reshape(pointsb(:,1),(/2/)),double_1d_a) call tsgEvaluate(grid,reshape(pointsb(:,2),(/2/)),double_1d_b) call tsgEvaluateBatch(grid,pointsb,2,double_2d_c) do i=1,3 if ( norm1d(double_2d_a(i,:)-double_2d_c(i,:)) > 1.d-11 .or. & ( abs(double_2d_a(i,1)-double_1d_a(i)) + abs(double_2d_a(i,2)-double_1d_b(i)) ) > 1.d-11 ) then write(*,*) "Mismatch in tsgEvaluateBatch: case 3, output ", i stop 1 endif enddo do i=4,4 if ( ( norm1d(double_2d_a(i,:)-double_2d_c(i,:)) < 1.d-8 ) .or. & ( abs(double_2d_a(i,1)-double_1d_a(i)) + abs(double_2d_a(i,2)-double_1d_b(i)) ) < 1.d-8 ) then write(*,*) "Mismatch in tsgEvaluateBatch: case 3, output ", i stop 1 endif enddo deallocate(double_2d_a, double_2d_b, double_2d_c, double_1d_a, double_1d_b, pointsb, points) allocate(double_2d_a(4,2), double_2d_c(4,2), double_1d_a(4), double_1d_b(4), pointsb(2,2)) pointsb = reshape( (/ 1./3.d0, 1./3.d0, pi/6.d0, -sqrt(2.d0)/2.d0 /), shape(pointsb) ) double_2d_a(1,:) = 0.3d0 double_2d_a(2,:) = pointsb(1,:) + pointsb(2,:) double_2d_a(3,:) = pointsb(1,:)**2 + pointsb(2,:)**2 + pointsb(1,:)*pointsb(2,:) double_2d_a(4,:) = pointsb(1,:)**3 + pointsb(2,:)**3 + pointsb(1,:)*(pointsb(2,:)**2) call tsgMakeLocalPolynomialGrid(grid, 2, 4, 2, 2, tsg_localp) points => tsgGetPoints(grid) allocate(double_2d_b(4,tsgGetNumPoints(grid))) double_2d_b(1,:) = 0.3d0 double_2d_b(2,:) = points(1,:) + points(2,:) double_2d_b(3,:) = points(1,:)**2 + points(2,:)**2 + points(1,:)*points(2,:) double_2d_b(4,:) = points(1,:)**3 + points(2,:)**3 + points(1,:)*(points(2,:)**2) call tsgLoadNeededPoints(grid, double_2d_b) call tsgEvaluate(grid,reshape(pointsb(:,1),(/2/)),double_1d_a) call tsgEvaluate(grid,reshape(pointsb(:,2),(/2/)),double_1d_b) call tsgEvaluateBatch(grid,pointsb,2,double_2d_c) do i=1,3 if ( norm1d(double_2d_a(i,:)-double_2d_c(i,:)) > 1.d-11 .or. & ( abs(double_2d_a(i,1)-double_1d_a(i)) + abs(double_2d_a(i,2)-double_1d_b(i)) ) > 1.d-11 ) then write(*,*) "Mismatch in tsgEvaluateBatch: case 4, output ", i stop 1 endif enddo do i=4,4 if ( ( norm1d(double_2d_a(i,:)-double_2d_c(i,:)) < 1.d-8 ) .or. & ( abs(double_2d_a(i,1)-double_1d_a(i)) + abs(double_2d_a(i,2)-double_1d_b(i)) ) < 1.d-8 ) then write(*,*) "Mismatch in tsgEvaluateBatch: case 4, output ", i stop 1 endif enddo deallocate(double_2d_a, double_2d_b, double_2d_c, double_1d_a, double_1d_b, pointsb, points) allocate(double_2d_a(4,2), double_2d_c(4,2), double_1d_a(4), double_1d_b(4), pointsb(2,2)) pointsb = reshape( (/ 1./3.d0, 1./3.d0, pi/6.d0, -sqrt(2.d0)/2.d0 /), shape(pointsb) ) double_2d_a(1,:) = 0.3d0 double_2d_a(2,:) = pointsb(1,:) + pointsb(2,:) double_2d_a(3,:) = pointsb(1,:)**2 + pointsb(2,:)**2 + pointsb(1,:)*pointsb(2,:) double_2d_a(4,:) = pointsb(1,:)**3 + pointsb(2,:)**3 + pointsb(1,:)*(pointsb(2,:)**2) call tsgMakeLocalPolynomialGrid(grid, 2, 4, 3, 3, tsg_localp) points => tsgGetPoints(grid) allocate(double_2d_b(4,tsgGetNumPoints(grid))) double_2d_b(1,:) = 0.3d0 double_2d_b(2,:) = points(1,:) + points(2,:) double_2d_b(3,:) = points(1,:)**2 + points(2,:)**2 + points(1,:)*points(2,:) double_2d_b(4,:) = points(1,:)**3 + points(2,:)**3 + points(1,:)*(points(2,:)**2) call tsgLoadNeededPoints(grid, double_2d_b) call tsgEvaluate(grid,reshape(pointsb(:,1),(/2/)),double_1d_a) call tsgEvaluate(grid,reshape(pointsb(:,2),(/2/)),double_1d_b) call tsgEvaluateBatch(grid,pointsb,2,double_2d_c) do i=1,4 if ( ( norm1d(double_2d_a(i,:)-double_2d_c(i,:)) > 1.d-11 ) .or. & ( abs(double_2d_a(i,1)-double_1d_a(i)) + abs(double_2d_a(i,2)-double_1d_b(i)) ) > 1.d-11 ) then write(*,*) "Mismatch in tsgEvaluateBatch: case 5, output ", i stop 1 endif enddo deallocate(double_2d_a, double_2d_b, double_2d_c, double_1d_a, double_1d_b, pointsb, points) call tsgMakeGlobalGrid(grid, 2, 1, 22, tsg_iptotal, tsg_chebyshev) points => tsgGetPoints(grid) allocate(double_2d_a(1,tsgGetNumPoints(grid))) double_2d_a(1,:) = exp( -points(1,:)**2 - points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) allocate(pointsb(2,1000),double_2d_b(1,1000),double_2d_c(1,1000)) rnd => random(2,1000) pointsb = -1.d0 + 2.d0 * rnd double_2d_b(1,:) = exp( -pointsb(1,:)**2 - pointsb(2,:)**2 ) call tsgEvaluateBatch(grid,pointsb,1000,double_2d_c) if ( norm2d(double_2d_b-double_2d_c) > 1.d-8 ) then write(*,*) "Mismatch in tsgEvaluateBatch: global grid with chebyshev points, output ", norm2d(double_2d_b-double_2d_c) stop 1 endif deallocate(points,pointsb,double_2d_a,double_2d_b,double_2d_c,rnd) !======================================================================= ! tsgEvaluateHierarchicalFunctions() !======================================================================= call tsgMakeGlobalGrid(grid, 3, 1, 4, tsg_level, tsg_fejer2) points => tsgGetPoints(grid); i_a = tsgGetNumPoints(grid) allocate(double_2d_a(i_a,i_a)) call tsgEvaluateHierarchicalFunctions(grid,points,i_a,double_2d_a) forall(i = 1:i_a) double_2d_a(i,i) = double_2d_a(i,i) - 1 if ( norm2d(double_2d_a) > 1.d-11 ) then write(*,*) "Mismatch in tsgEvaluateHierarchy: lagrange polynomials do not form identity" stop 1 endif deallocate(points, double_2d_a) call tsgMakeSequenceGrid(grid, 2, 1, 2, tsg_level, tsg_leja) allocate(points(2,6), double_2d_a(6,6), double_2d_b(6,6)) points = reshape( (/ 0.33d0, 0.25d0, -0.270d0, 0.39d0, 0.970d0, -0.760d0, & -0.44d0, 0.21d0, -0.813d0, 0.03d0, -0.666d0, 0.666d0 /), shape(points) ) double_2d_a(1,:) = 1 double_2d_a(2,:) = points(2,:) double_2d_a(3,:) = 0.5d0 * points(2,:) * ( points(2,:) - 1.d0 ) double_2d_a(4,:) = points(1,:) double_2d_a(5,:) = points(1,:) * points(2,:) double_2d_a(6,:) = 0.5d0 * points(1,:) * ( points(1,:) - 1.d0 ) call tsgEvaluateHierarchicalFunctions(grid,points,6,double_2d_b) if ( norm2d(double_2d_a-double_2d_b) > 1.d-11 ) then write(*,*) "Mismatch in tsgEvaluateHierarchicalFunctions: sequence grid test" stop 1 endif deallocate(points, double_2d_a, double_2d_b) call tsgMakeLocalPolynomialGrid(grid, 2, 1, 4, 1, tsg_localp) points => tsgGetPoints(grid) i_a = tsgGetNumPoints(grid) i_b = 13 allocate(double_2d_a(1,i_a), double_2d_b(1,i_b), double_2d_c(i_a,i_b), double_1d_b(i_b), pointsb(2,i_b)) double_2d_a(1,:) = exp( -points(1,:)**2 - 2.d0 * points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) rnd => random(2,i_b) pointsb = -1.d0 + 2.d0 * rnd call tsgEvaluateBatch(grid,pointsb,i_b,double_2d_b) call tsgEvaluateHierarchicalFunctions(grid,pointsb,i_b,double_2d_c) weights => tsgGetHierarchicalCoefficients(grid) double_1d_b = matmul( weights, double_2d_c ) if ( norm1d(double_1d_b-double_2d_b(1,:)) > 1.d-11 ) then write(*,*) "Mismatch in tsgEvaluateHierarchicalFunctions: local grid test" stop 1 endif allocate( double_1d_a(tsgGetNumPoints(grid)) ) call tsgGetHierarchicalCoefficientsStatic(grid, double_1d_a) double_1d_b = matmul( double_1d_a, double_2d_c ) if ( norm1d(double_1d_b-double_2d_b(1,:)) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetHierarchicalCoefficientsStatic: local grid test" stop 1 endif deallocate(points,double_1d_a,double_2d_a,double_2d_b,double_2d_c,weights,double_1d_b,rnd,pointsb) call tsgMakeLocalPolynomialGrid(grid, 2, 1, 4, 1, tsg_localp) points => tsgGetPoints(grid) i_a = tsgGetNumPoints(grid) i_b = 13 allocate(double_2d_a(1,i_a), double_2d_b(1,i_b), double_1d_b(i_b), pointsb(2,i_b)) double_2d_a(1,:) = exp( -points(1,:)**2 - 2.d0 * points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) rnd => random(2,i_b) pointsb = -1.d0 + 2.d0 * rnd call tsgEvaluateBatch(grid,pointsb,i_b,double_2d_b) call tsgEvaluateSparseHierarchicalFunctions(grid,pointsb, i_b, int_pnt_1d_a, int_pnt_1d_b, double_pnt_1d_a) weights => tsgGetHierarchicalCoefficients(grid) double_1d_b = sparse_matmul( int_pnt_1d_a, int_pnt_1d_b, double_pnt_1d_a, weights ) if ( norm1d(double_1d_b-double_2d_b(1,:)) > 1.d-11 ) then write(*,*) "Mismatch in tsgEvaluateSparseHierarchicalFunctions: local grid test" stop 1 endif deallocate(points,double_2d_a,double_2d_b,weights,double_1d_b,rnd,pointsb,int_pnt_1d_a,int_pnt_1d_b,double_pnt_1d_a) ! test reading a complex matrix call tsgMakeFourierGrid(grid, 2, 1, 4, tsg_level) points => tsgGetPoints(grid) i_a = tsgGetNumPoints(grid) i_b = 13 allocate(double_2d_a(1,i_a), double_2d_b(1,i_b), double_2d_c(i_b,2*i_a), & double_1d_a(i_b), double_1d_b(i_b), double_1d_c(i_b), pointsb(2,i_b), double_1d_d(2*i_a)) double_2d_a(1,:) = exp( -points(1,:)**2 - 2.d0 * points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) rnd => random(2,i_b) pointsb = -1.d0 + 2.d0 * rnd call tsgEvaluateBatch(grid,pointsb,i_b,double_2d_b) allocate(dcmplx_1d_a(i_a),dcmplx_2d_c(i_a,i_b)) call tsgEvaluateComplexHierarchicalFunctions(grid,pointsb,i_b,dcmplx_2d_c) call tsgGetComplexHierarchicalCoefficientsStatic(grid, dcmplx_1d_a) double_1d_b = real(matmul(dcmplx_1d_a,dcmplx_2d_c)) dcmplx_pnt_1d_a => tsgGetComplexHierarchicalCoefficients(grid) double_1d_c = real(matmul(dcmplx_pnt_1d_a,dcmplx_2d_c)) if ( norm1d(double_1d_b - double_2d_b(1,:)) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetComplexHierarchicalCoefficientsStatic: fourier grid test 1" stop 1 endif if ( norm1d(double_1d_c - double_2d_b(1,:)) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetComplexHierarchicalCoefficientsStatic: fourier grid test 2" stop 1 endif deallocate(points,pointsb,double_2d_a,double_2d_b,double_2d_c,double_1d_a,double_1d_b,double_1d_c,double_1d_d,rnd) deallocate(dcmplx_pnt_1d_a,dcmplx_1d_a,dcmplx_2d_c) ! load coefficients i_a = 13 allocate( double_2d_b(1,i_a), double_2d_c(1,i_a), pointsb(2,i_a) ) call tsgMakeLocalPolynomialGrid(grid, 2, 1, 5, 1, tsg_semi_localp) call tsgMakeLocalPolynomialGrid(grid_II, 2, 1, 5, 1, tsg_semi_localp) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) rnd => random(2,i_a) pointsb = -1.d0 + 2.d0 * rnd allocate( double_2d_a(1,i_b), double_2d_d(i_b,i_b) ) double_2d_a(1,:) = exp( -points(1,:)**2 - 2.d0 * points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) double_pnt_1d_b => tsgGetHierarchicalCoefficients(grid) call tsgSetHierarchicalCoefficients(grid_II,double_pnt_1d_b) call tsgEvaluateBatch(grid,pointsb,i_a,double_2d_b) call tsgEvaluateBatch(grid_II,pointsb,i_a,double_2d_c) if ( norm2d(double_2d_b - double_2d_c) > 1.d-11 ) then write(*,*) "Mismatch in setHierarchicalCoefficients: localp grid solve ", norm2d(double_2d_b - double_2d_c) stop 1 endif deallocate(points,pointsb,double_2d_a,double_2d_b,double_2d_c,double_2d_d,double_pnt_1d_b,rnd) call tsgMakeLocalPolynomialGrid(grid, 2, 1, 5, 1, tsg_semi_localp) call tsgMakeLocalPolynomialGrid(grid_II, 2, 1, 5, 1, tsg_semi_localp) call tsgSetDomainTransform(grid, (/-1.d0, 7.d0/), (/2.d0, 9.d0/)) call tsgSetDomainTransform(grid_II, (/-1.d0, 7.d0/), (/2.d0, 9.d0/)) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) i_a = 13 allocate(double_2d_a(1,i_b), double_2d_b(1,i_a), double_2d_c(1,i_a), double_2d_d(i_b,i_b), pointsb(2,i_a)) double_2d_a(1,:) = exp( -points(1,:)**2 - 2.d0 * points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) double_pnt_1d_b => tsgGetHierarchicalCoefficients(grid) call tsgSetHierarchicalCoefficients(grid_II,double_pnt_1d_b) rnd => random(2,i_a) pointsb = -1.d0 + 2.d0 * rnd call tsgEvaluateBatch(grid, pointsb, i_a, double_2d_b) call tsgEvaluateBatch(grid_II, pointsb, i_a, double_2d_c) if ( norm2d(double_2d_b - double_2d_c) > 1.d-11 ) then write(*,*) "Mismatch in setHierarchicalCoefficients: local grid solve, transform" stop 1 endif deallocate(points,pointsb,double_2d_a,double_2d_b,double_2d_c,double_2d_d,double_pnt_1d_b,rnd) call tsgMakeSequenceGrid(grid, 2, 1, 5, tsg_level, tsg_rleja) call tsgMakeSequenceGrid(grid_II, 2, 1, 5, tsg_level, tsg_rleja) call tsgSetDomainTransform(grid, (/1.d0, 1.d0/), (/2.d0, 2.d0/)) call tsgSetDomainTransform(grid_II, (/1.d0, 1.d0/), (/2.d0, 2.d0/)) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) i_a = 13 allocate(double_2d_a(1,i_b), double_2d_b(1,i_a), double_2d_c(1,i_a), double_2d_d(i_b,i_b), pointsb(2,i_a)) double_2d_a(1,:) = exp( -points(1,:)**2 - 2.d0 * points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) double_pnt_1d_b => tsgGetHierarchicalCoefficients(grid) call tsgSetHierarchicalCoefficients(grid_II,double_pnt_1d_b) rnd => random(2,i_a) pointsb = -1.d0 + 2.d0 * rnd call tsgEvaluateBatch(grid, pointsb, i_a, double_2d_b) call tsgEvaluateBatch(grid_II, pointsb, i_a, double_2d_c) if ( norm2d(double_2d_b - double_2d_c) > 1.d-11 ) then write(*,*) "Mismatch in setHierarchicalCoefficients: sequence grid solve, transform" stop 1 endif deallocate(points,pointsb,double_2d_a,double_2d_b,double_2d_c,double_2d_d,double_pnt_1d_b,rnd) call tsgMakeWaveletGrid(grid, 1, 1, 1, 3) points => tsgGetHierarchicalSupport(grid) double_2d_b = reshape( (/ 2.d0, 2.d0, 2.d0, 2.d0, 2.d0, 2.d0, 2.d0, 2.d0, 2.d0, & 1.d4, 1.d4, 1.d4, 1.d4, 1.d4, 1.d4, 1.d4, 1.d4 /), shape(points) ) if ( norm2d(points - double_2d_b) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetHierarchicalSupport: wavelet grid" stop 1 endif deallocate(points, double_2d_b) !======================================================================= ! tsgIntegrate() !======================================================================= call tsgMakeGlobalGrid(grid, 1, 1, 2, tsg_level, tsg_gauss_hermite, alpha=0.d0, beta=0.d0) points => tsgGetPoints(grid) i_a = tsgGetNumPoints(grid) allocate(double_2d_a(1,i_a),double_1d_a(tsgGetNumOutputs(grid))) double_2d_a(1,:) = points(1,:)**2 call tsgLoadNeededPoints(grid, double_2d_a) call tsgIntegrate(grid, double_1d_a) if ( abs(double_1d_a(1) - sqrt(pi)/2.d0) > 1.d-11 ) then write(*,*) "Mismatch in tsgIntegrate: case 1" stop 1 endif deallocate(points, double_2d_a, double_1d_a) call tsgMakeGlobalGrid(grid, 1, 1, 2, tsg_level, tsg_gauss_hermite, alpha=2.d0, beta=0.d0) points => tsgGetPoints(grid) i_a = tsgGetNumPoints(grid) allocate(double_2d_a(1,i_a),double_1d_a(tsgGetNumOutputs(grid))) double_2d_a(1,:) = sqrt(2.d0) call tsgLoadNeededPoints(grid, double_2d_a) call tsgIntegrate(grid, double_1d_a) if ( abs(double_1d_a(1) - sqrt(2.d0*pi)/2.d0) > 1.d-11 ) then write(*,*) "Mismatch in tsgIntegrate: case 2" stop 1 endif deallocate(points, double_2d_a, double_1d_a) write(*,*) "Core I/O and evaluate: PASS" !======================================================================= ! tsgGetInterpolationWeights() !======================================================================= i_a = 32 call tsgMakeGlobalGrid(grid, 2, 1, 4, tsg_level, tsg_fejer2) call tsgMakeGlobalGrid(grid_II, 2, 1, 4, tsg_level, tsg_fejer2) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) allocate( pointsb(2,i_a), double_2d_a(1,i_b), double_2d_b(1,i_a), double_2d_c(1,i_a) ) rnd => random(2,i_a) pointsb = -1.d0 + 2.d0 * rnd double_2d_a(1,:) = exp( -points(1,:)**2 - 2.d0 * points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) call tsgEvaluateBatch(grid, pointsb, i_a, double_2d_b) do i = 1,i_a double_pnt_1d_a => tsgGetInterpolationWeights(grid_II, pointsb(:,i)) double_2d_c(:,i) = matmul(double_2d_a,double_pnt_1d_a) deallocate(double_pnt_1d_a) enddo if ( norm2d(double_2d_b - double_2d_c) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetInterpolationWeights: global case" stop 1 endif do i = 1,i_a allocate( double_1d_a(tsgGetNumPoints(grid)) ) call tsgGetInterpolationWeightsStatic(grid, pointsb(:,i), double_1d_a) double_2d_c(:,i) = matmul(double_2d_a,double_1d_a) deallocate(double_1d_a) enddo if ( norm2d(double_2d_b - double_2d_c) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetInterpolationWeights: global case" stop 1 endif deallocate(points, pointsb, double_2d_a, double_2d_b, double_2d_c, rnd) i_a = 32 call tsgMakeSequenceGrid(grid, 2, 1, 7, tsg_level, tsg_min_delta) call tsgMakeSequenceGrid(grid_II, 2, 1, 7, tsg_level, tsg_min_delta) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) allocate( pointsb(2,i_a), double_2d_a(1,i_b), double_2d_b(1,i_a), double_2d_c(1,i_a) ) rnd => random(2,i_a) pointsb = -1.d0 + 2.d0 * rnd double_2d_a(1,:) = exp( -points(1,:)**2 - 2.d0 * points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) call tsgEvaluateBatch(grid, pointsb, i_a, double_2d_b) do i = 1,i_a double_pnt_1d_a => tsgGetInterpolationWeights(grid_II, pointsb(:,i)) double_2d_c(:,i) = matmul(double_2d_a,double_pnt_1d_a) deallocate(double_pnt_1d_a) enddo if ( norm2d(double_2d_b - double_2d_c) > 1.d-11 ) then write(*,*) "Mismatch in tsgGetInterpolationWeights: global case" stop 1 endif deallocate(points, pointsb, double_2d_a, double_2d_b, double_2d_c, rnd) !======================================================================= ! tsgEstimateAnisotropicCoefficients() !======================================================================= call tsgMakeGlobalGrid(grid, 2, 1, 9, tsg_level, tsg_rleja) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) allocate( double_2d_a(1,i_b) ) double_2d_a(1,:) = exp( points(1,:) + points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) int_pnt_1d_a => tsgEstimateAnisotropicCoefficients(grid,tsg_iptotal,1) if ( abs( int_pnt_1d_a(1)/dble(int_pnt_1d_a(2)) - 2.0 ) > 0.2 ) then write(*,*) "Mismatch in tsgEstimateAnisotropicCoefficients: total degree" stop 1 endif deallocate(int_pnt_1d_a) int_pnt_1d_a => tsgEstimateAnisotropicCoefficients(grid,tsg_ipcurved,1) if ( size(int_pnt_1d_a) .ne. 4 ) then write(*,*) "Mismatch in tsgEstimateAnisotropicCoefficients: curved dimensions" stop 1 endif if ( (abs( int_pnt_1d_a(1)/dble(int_pnt_1d_a(2)) - 2.0 ) > 0.2) & .or. (int_pnt_1d_a(3)>0) .or. (int_pnt_1d_a(4)>0) ) then write(*,*) "Mismatch in tsgEstimateAnisotropicCoefficients: curved" stop 1 endif deallocate(int_pnt_1d_a) deallocate(points, double_2d_a) !======================================================================= ! tsgSetAnisotropicRefinement() !======================================================================= call tsgMakeSequenceGrid(grid, 3, 1, 3, tsg_level, tsg_leja, levelLimits=(/3,2,1/)) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) if ( check_points( points(1,:), (/0.d0,-1.d0,1.d0,1.d0/sqrt(3.d0)/), (/12345.d0/) ) .or. & check_points( points(2,:), (/0.d0,-1.d0,1.d0/), (/1.d0/sqrt(3.d0)/) ) .or. & check_points( points(3,:), (/0.d0,1.d0/), (/-1.d0,1.d0/sqrt(3.d0)/) ) ) then write(*,*) "Mismatch in tsgSetAnisotropicRefinement: limits in make" stop 1 endif allocate( double_2d_a(1,i_b) ) double_2d_a(1,:) = exp( -points(1,:)**2 - points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) call tsgSetAnisotropicRefinement( grid, tsg_iptotal, 5, 1 ) pointsb => tsgGetNeededPoints(grid) if ( size(pointsb,2) .eq. 0 ) then write(*,*) "Mismatch in tsgSetAnisotropicRefinement: did not refine" stop 1 endif if ( check_points( points(2,:), (/12345.d0/), (/1.d0/sqrt(3.d0)/) ) .or. & check_points( points(3,:), (/12345.d0/), (/-1.d0,1.d0/sqrt(3.d0)/) ) ) then write(*,*) "Mismatch in tsgSetAnisotropicRefinement: limits refine using existing limits" stop 1 endif deallocate( pointsb ) call tsgSetAnisotropicRefinement(grid,tsg_iptotal,10,1,levelLimits=(/3,2,2/)) pointsb => tsgGetNeededPoints(grid) if ( size(pointsb) .eq. 0 ) then write(*,*) "Mismatch in tsgSetAnisotropicRefinement: did not refine" stop 1 endif if ( check_points( points(2,:), (/12345.d0/), (/1.d0/sqrt(3.d0)/) ) .or. & check_points( points(3,:), (/-1.d0/), (/1.d0/sqrt(3.d0)/) ) ) then write(*,*) "Mismatch in tsgSetAnisotropicRefinement: limits refine using new limits" stop 1 endif deallocate( points, pointsb, double_2d_a ) !======================================================================= ! tsgSetLocalSurplusRefinement() !======================================================================= call tsgMakeLocalPolynomialGrid(grid, 3, 1, 3, 1, tsg_localp, levelLimits=(/1,2,3/)) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) if ( check_points( points(1,:), (/0.d0,-1.d0,1.d0/), (/0.5d0,-0.5d0,-0.75d0,-0.25d0,0.25d0,0.75d0/) ) .or. & check_points( points(2,:), (/0.d0,-1.d0,1.d0,0.5d0,-0.5d0/), (/-0.75d0,-0.25d0,0.25d0,0.75d0/) ) .or. & check_points( points(3,:), (/0.d0,-1.d0,1.d0,0.5d0,-0.5d0,-0.75d0,-0.25d0,0.25d0,0.75d0/), (/12345.d0/) ) ) then write(*,*) "Mismatch in tsgSetLocalSurplusRefinement: limits in make" stop 1 endif allocate( double_2d_a(1,i_b) ) double_2d_a(1,:) = exp( -points(1,:)**2 - points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) call tsgSetLocalSurplusRefinement(grid,1.d-8,tsg_classic,1) if ( tsgGetNumNeeded(grid) .eq. 0 ) then write(*,*) "Mismatch in tsgSetLocalSurplusRefinement: did not refine local polynomial" stop 1 endif if ( check_points( points(1,:), (/12345.d0/), (/0.5d0,-0.5d0,-0.75d0,-0.25d0,0.25d0,0.75d0/) ) .or. & check_points( points(2,:), (/12345.d0/), (/-0.75d0,-0.25d0,0.25d0,0.75d0/) ) .or. & check_points( points(3,:), (/12345.d0/), (/12345.d0/) ) ) then write(*,*) "Mismatch in tsgSetSurplusRefinement: limits refine using existing limits" stop 1 endif call tsgSetLocalSurplusRefinement(grid,1.d-8,tsg_classic,1,(/2,2,3/)) if ( tsgGetNumNeeded(grid) .eq. 0 ) then write(*,*) "Mismatch in tsgSetLocalSurplusRefinement: did not refine on second pass" stop 1 endif if ( check_points( points(1,:), (/0.5d0,-0.5d0/), (/-0.75d0,-0.25d0,0.25d0,0.75d0/) ) .or. & check_points( points(2,:), (/12345.d0/), (/-0.75d0,-0.25d0,0.25d0,0.75d0/) ) ) then write(*,*) "Mismatch in tsgSetSurplusRefinement: limits refine using new limits" stop 1 endif deallocate(points, double_2d_a) !======================================================================= ! tsgClearRefinement() !======================================================================= call tsgMakeLocalPolynomialGrid(grid, 3, 1, 4, 2, tsg_localp, levelLimits=(/300,300,300/)) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) allocate( double_2d_a(1,i_b) ) double_2d_a(1,:) = exp( -points(1,:)**2 - 0.5*points(2,:)**2 - 2.d0*points(3,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) if ( tsgGetNumNeeded(grid) > 0 ) then write(*,*) "Mismatch in cancel refine: did not load values" stop 1 endif call tsgSetLocalSurplusRefinement(grid,1.d-4,tsg_directional) if ( tsgGetNumNeeded(grid) .eq. 0 ) then write(*,*) "Mismatch in cancel refine: did not set refinement at output -1" stop 1 endif call tsgClearRefinement(grid) if ( tsgGetNumNeeded(grid) > 0 ) then write(*,*) "Mismatch in cancel refine: did not cancel the refinement" stop 1 endif deallocate(points, double_2d_a) !======================================================================= ! tsgMergeRefinement() !======================================================================= call tsgMakeGlobalGrid(grid, 2, 1, 4, tsg_level, tsg_fejer2) call tsgMakeGlobalGrid(grid_II, 2, 1, 4, tsg_level, tsg_fejer2) points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) allocate( double_2d_a(1,i_b) ) double_2d_a(1,:) = exp( -points(1,:)**2 - points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) call tsgLoadNeededPoints(grid_II, double_2d_a) call tsgSetAnisotropicRefinement( grid, tsg_iptotal, 10, 1 ) call tsgSetAnisotropicRefinement( grid_II, tsg_iptotal, 10, 1 ) deallocate(points, double_2d_a) points => tsgGetNeededPoints(grid); i_b = tsgGetNumNeeded(grid) allocate( double_2d_a(1,i_b) ) double_2d_a(1,:) = exp( -points(1,:)**2 - points(2,:)**2 ) call tsgLoadNeededPoints(grid, double_2d_a) call tsgMergeRefinement(grid_II) deallocate(points, double_2d_a) i_a = 20 points => tsgGetPoints(grid); i_b = tsgGetNumPoints(grid) pointsb => tsgGetPoints(grid_II); i_c = tsgGetNumPoints(grid_II) if ( norm2d(points-pointsb) > 1.d-11 )then write(*,*) "Mismatch in tsgMergeRefine(): case 2, tsgGetPoints()" stop 1 endif deallocate(points, pointsb) allocate(points(2,i_a), double_2d_a(1,i_a)) rnd => random(2,i_a) points = -1.d0 + 2.d0 * rnd call tsgEvaluateBatch(grid_II,points,i_a,double_2d_a) if ( norm2d(double_2d_a) > 1.d-11 ) then write(*,*) "Mismatch in tsgMergeRefine(): case 3, tsgEvaluate() not zero" stop 1 endif deallocate(rnd, points, double_2d_a) points => tsgGetPoints(grid_II); i_b = tsgGetNumPoints(grid_II) allocate( double_2d_a(1,i_b) ) double_2d_a(1,:) = exp( -points(1,:)**2 - points(2,:)**2 ) call tsgLoadNeededPoints(grid_II, double_2d_a) deallocate(points, double_2d_a) i_a = 30 allocate( points(2,i_a), double_2d_a(1,i_a), double_2d_b(1,i_a) ) rnd => random(2,i_a) points = -1.d0 + 2.d0 * rnd call tsgEvaluateBatch(grid, points, i_a, double_2d_a) call tsgEvaluateBatch(grid_II, points, i_a, double_2d_b) if ( norm2d(double_2d_a-double_2d_b) > 1.d-11 )then write(*,*) "Mismatch in tsgMergeRefine(): case 3, tsgEvaluate() not equal" stop 1 endif deallocate(points, double_2d_a, double_2d_b, rnd) write(*,*) "Refinement functions: PASS" call tsgDeallocateGrid(grid) call tsgDeallocateGrid(grid_II) contains function random(n,m) result(res) integer :: n, m double precision, pointer :: res(:,:) allocate(res(n,m)) call random_number(res) end function function norm(x,n) result(res) integer :: n double precision :: x(n) double precision :: res res = sqrt(sum(x**2)) end function function norm1d(x) result(res) double precision :: x(:) double precision :: res res = sqrt(sum(x**2)) end function function norm2d(x) result(res) double precision :: x(:,:) double precision :: res res = sqrt(sum(x**2)) end function function check_points(points,mustHave,mustNotHave) result(res) double precision :: points(:), mustHave(:), mustNotHave(:) logical :: res integer :: i, j res = .false. do i = 1,size(points) if ( any(points(i).ne.mustHave) .and. any(points(i).eq.mustNotHave) ) then res = .true. exit endif enddo end function subroutine print_vector(vec) double precision :: vec(:) integer :: i do i = 1,size(vec) write(*,'(f6.3 a)',advance='no') vec(i), " " enddo write(*,*) end subroutine subroutine print_array(arr) double precision :: arr(:,:) integer :: shp(2), i, j shp = shape(arr) do i = 1,shp(1) do j = 1,shp(2) write(*,'(f6.3 a)',advance='no') arr(i,j), " " enddo write(*,*) enddo end subroutine function sparse_matmul(pntr,indx,val,vec) result(res) integer :: pntr(:), indx(:) double precision :: val(:), vec(:) integer :: i, j double precision :: res(size(pntr)-1) res = 0.d0 do i = 1,size(pntr)-1 do j = pntr(i)+1,pntr(i+1) res(i) = res(i) + val(j) * vec(indx(j)+1) enddo enddo end function function Re_complex_matmul(mat,vec) result(res) double precision :: mat(:,:), vec(:) integer :: i, j integer :: shp(2) double precision :: res(size(mat,1)) shp = shape(mat) res = 0.d0 do i = 1,shp(1) do j = 1,shp(2)/2 res(i) = res(i) + mat(i,2*j-1) * vec(2*j-1) - mat(i,2*j) * vec(2*j) enddo enddo end function end program FORTESTER TASMANIAN-8.1/InterfaceFortran/mpitester.f90000066400000000000000000000104141470551176200204750ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== program MPITESTER use TasmanianSG use mpi implicit none integer :: ierr, me integer :: num_points type(TasmanianSparseGrid) :: grid, reference_grid call MPI_Init(ierr) call MPI_Comm_rank(MPI_COMM_WORLD, me, ierr) if (ierr /= MPI_SUCCESS) then write(*,*) "ERROR: failed to initialize MPI" stop 1 endif !write(*,*) "HELLO CRUEL WORLD from me: ", me, MPI_STATUS_SIZE call tsgAllocateGrid(grid) call tsgAllocateGrid(reference_grid) call tsgMakeSequenceGrid(reference_grid, 3, 1, 3, tsg_level, tsg_rleja) if (me == 0) then call tsgMPIGridSend(reference_grid, 1, 11, MPI_COMM_WORLD, ierr) endif if (me == 1) then call tsgMPIGridRecv(grid, 0, 11, MPI_COMM_WORLD, MPI_STATUS_IGNORE, ierr) if (tsgGetNumPoints(grid) /= tsgGetNumPoints(reference_grid)) then write(*,*) "ERROR: failed to receive the grid" stop 1 endif call tsgDeallocateGrid(grid) ! reset the grid call tsgAllocateGrid(grid) endif if (ierr /= MPI_SUCCESS) then write(*,*) "ERROR: failed at send/recv stage" stop 1 endif if (me == 2) then call tsgMPIGridBcast(reference_grid, 2, MPI_COMM_WORLD, ierr) call tsgCopyGrid(grid, reference_grid) endif if (me /= 2) then call tsgMPIGridBcast(grid, 2, MPI_COMM_WORLD, ierr) endif if (tsgGetNumPoints(grid) /= tsgGetNumPoints(reference_grid)) then write(*,*) "ERROR: failed to receive the grid" stop 1 endif if (ierr /= MPI_SUCCESS) then write(*,*) "ERROR: failed at bcast stage" stop 1 endif call tsgDeallocateGrid(grid) call tsgDeallocateGrid(reference_grid) if (me == 0) then write(*,*) "" write(*,*) " MPI Send/Recv/Bcast Pass" write(*,*) "" endif call MPI_Finalize(ierr) end program MPITESTER TASMANIAN-8.1/InterfaceFortran/tsgC2Fortran.cpp000066400000000000000000000342661470551176200211760ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_C2FORT_CPP #define __TSG_C2FORT_CPP #include "TasmanianAddons.hpp" using std::cerr; using std::endl; using namespace TasGrid; extern "C" void tsgc2fstr_(int *length, const char *str); extern "C" void tsgc2fvec_(int *length, double *vect); extern "C" void tsgc2fmat_(int *rows, int *cols, double *mat); extern "C"{ //////////////////////////////////////////////////////////////////////// // MAIN INTERFACE //////////////////////////////////////////////////////////////////////// void tsggvm_(int *ver){ *ver = TasmanianSparseGrid::getVersionMajor(); } void tsggvn_(int *ver){ *ver = TasmanianSparseGrid::getVersionMinor(); } void tsggli_(){ // this is clumsy, may have to think of something else const char *lic = TasmanianSparseGrid::getLicense(); int l = 0; while(lic[l] != '\0') l++; tsgc2fstr_(&l, lic); } // read/write void tsgwri_(TasmanianSparseGrid **grid, const char *filename, int *binary){ (*grid)->write(filename, (*binary != 0)); } void tsgrea_(TasmanianSparseGrid **grid, const char *filename, int *status){ try{ (*grid)->read(filename); *status = 1; }catch(std::runtime_error &e){ cerr << e.what() << endl; *status = 0; } } void tsgalloc_(TasmanianSparseGrid **grid){ (*grid) = new TasmanianSparseGrid(); } void tsgfree_(TasmanianSparseGrid **grid){ delete (*grid); } // create void tsgmg_(TasmanianSparseGrid **grid, int *dimensions, int *outputs, int *depth, int *type, int *rule, int *opt_flags, const int *aniso_weights, double *alpha, double *beta, const char *customRuleFilename, const int *llimits){ const int *aw = (opt_flags[0] != 0 ) ? aniso_weights : nullptr; double al = (opt_flags[1] != 0 ) ? *alpha : 0.0; double be = (opt_flags[2] != 0 ) ? *beta : 0.0; const char *cfn = (opt_flags[3] != 0 ) ? customRuleFilename : nullptr; const int *ll = (opt_flags[4] != 0 ) ? llimits : nullptr; (*grid)->makeGlobalGrid(*dimensions, *outputs, *depth, IO::getDepthTypeInt(*type), IO::getRuleInt(*rule), aw, al, be, cfn, ll); } void tsgms_(TasmanianSparseGrid **grid, int *dimensions, int *outputs, int *depth, int *type, int *rule, int *opt_flags, const int *aniso_weights, const int *llimits){ const int *aw = (opt_flags[0] != 0 ) ? aniso_weights : nullptr; const int *ll = (opt_flags[1] != 0 ) ? llimits : nullptr; (*grid)->makeSequenceGrid(*dimensions, *outputs, *depth, IO::getDepthTypeInt(*type), IO::getRuleInt(*rule), aw, ll); } void tsgml_(TasmanianSparseGrid **grid, int *dimensions, int *outputs, int *depth, int *opt_flags, int *order, int *rule, const int *llimits){ int ru = (opt_flags[0] != 0) ? *rule : 1; int ord = (opt_flags[1] != 0) ? *order : 1; const int *ll = (opt_flags[2] != 0) ? llimits : nullptr; (*grid)->makeLocalPolynomialGrid(*dimensions, *outputs, *depth, ord, IO::getRuleInt(ru), ll); } void tsgmw_(TasmanianSparseGrid **grid, int *dimensions, int *outputs, int *depth, int *opt_flags, int *order, const int *llimits){ int ord = (opt_flags[0] != 0) ? *order : 1; const int *ll = (opt_flags[1] != 0) ? llimits : nullptr; (*grid)->makeWaveletGrid(*dimensions, *outputs, *depth, ord, ll); } void tsgmf_(TasmanianSparseGrid **grid, int *dimensions, int *outputs, int *depth, int *type, int *opt_flags, const int *aniso_weights, const int *llimits){ const int *aw = (opt_flags[0] != 0 ) ? aniso_weights : nullptr; const int *ll = (opt_flags[1] != 0 ) ? llimits : nullptr; (*grid)->makeFourierGrid(*dimensions, *outputs, *depth, IO::getDepthTypeInt(*type), aw, ll); } // copy/updare void tsgcp_(TasmanianSparseGrid **grid, TasmanianSparseGrid **source){ (*grid)->copyGrid(*source); } void tsgug_(TasmanianSparseGrid **grid, int *depth, int *type, int *opt_flags, const int *anisotropic_weights){ const int *aw = (opt_flags[0] != 0) ? anisotropic_weights : nullptr; (*grid)->updateGlobalGrid(*depth, IO::getDepthTypeInt(*type), aw); } void tsgus_(TasmanianSparseGrid **grid, int *depth, int *type, int *opt_flags, const int *anisotropic_weights){ const int *aw = (opt_flags[0] != 0) ? anisotropic_weights : nullptr; (*grid)->updateSequenceGrid(*depth, IO::getDepthTypeInt(*type), aw); } // getAlpha/Beta/Order/Dims/Outs/Rule // void tsggal_(TasmanianSparseGrid **grid, double *alpha){ *alpha = (*grid)->getAlpha(); } void tsggbe_(TasmanianSparseGrid **grid, double *beta){ *beta = (*grid)->getBeta(); } void tsggor_(TasmanianSparseGrid **grid, int *order){ *order = (*grid)->getOrder(); } void tsggnd_(TasmanianSparseGrid **grid, int *dims){ *dims = (*grid)->getNumDimensions(); } void tsggno_(TasmanianSparseGrid **grid, int *outs){ *outs = (*grid)->getNumOutputs(); } void tsggru_(TasmanianSparseGrid **grid, int *rule){ *rule = IO::getRuleInt((*grid)->getRule()); } // getNumNeeded/Loaded/Points void tsggnn_(TasmanianSparseGrid **grid, int *num_points){ *num_points = (*grid)->getNumNeeded(); } void tsggnl_(TasmanianSparseGrid **grid, int *num_points){ *num_points = (*grid)->getNumLoaded(); } void tsggnp_(TasmanianSparseGrid **grid, int *num_points){ *num_points = (*grid)->getNumPoints(); } // getLoaded/Needed/Points void tsgglp_(TasmanianSparseGrid **grid, double *points){ (*grid)->getLoadedPoints(points); } void tsggdp_(TasmanianSparseGrid **grid, double *points){ (*grid)->getNeededPoints(points); } void tsggpp_(TasmanianSparseGrid **grid, double *points){ (*grid)->getPoints(points); } // getQuadrature/InterpolationWeights void tsggqw_(TasmanianSparseGrid **grid, double *weights){ (*grid)->getQuadratureWeights(weights); } void tsggiw_(TasmanianSparseGrid **grid, const double *x, double *weights){ (*grid)->getInterpolationWeights(x,weights); } // set/is/clear/getDomainTransform void tsgsdt_(TasmanianSparseGrid **grid, const double *transform_a, const double *transform_b){ (*grid)->setDomainTransform(transform_a, transform_b); } void tsgidt_(TasmanianSparseGrid **grid, int *result){ *result = ((*grid)->isSetDomainTransfrom()) ? 1 : 0; } void tsgcdt_(TasmanianSparseGrid **grid){ (*grid)->clearDomainTransform(); } void tsggdt_(TasmanianSparseGrid **grid, double *transform_a, double *transform_b){ (*grid)->getDomainTransform(transform_a, transform_b); } // loadNeededPoints void tsglnp_(TasmanianSparseGrid **grid, const double *vals){ (*grid)->loadNeededPoints(vals); } // evaluate/Fast/Batch/integrate void tsgeva_(TasmanianSparseGrid **grid, const double *x, double *y){ (*grid)->evaluate(x, y); } void tsgevf_(TasmanianSparseGrid **grid, const double *x, double *y){ (*grid)->evaluateFast(x, y); } void tsgevb_(TasmanianSparseGrid **grid, const double *x, int *num_x, double *y){ (*grid)->evaluateBatch(x, (*num_x), y); } void tsgint_(TasmanianSparseGrid **grid, double *q){ (*grid)->integrate(q); } // hierarchical functions/coefficients void tsgehf_(TasmanianSparseGrid **grid, const double *x, int *num_x, double *y){ (*grid)->evaluateHierarchicalFunctions(x, (*num_x), y);} void tsgehs_(TasmanianSparseGrid **grid, const double *x, int *num_x, int *pntr, int *indx, double *vals){ (*grid)->evaluateSparseHierarchicalFunctionsStatic(x, *num_x, pntr, indx, vals);} void tsgehz_(TasmanianSparseGrid **grid, const double *x, int *num_x, int *num_nz){ *num_nz = (*grid)->evaluateSparseHierarchicalFunctionsGetNZ(x, *num_x);} void tsgghc_(TasmanianSparseGrid **grid, double *c){ const double *cc = (*grid)->getHierarchicalCoefficients(); (*grid)->isFourier() ? std::copy(cc, cc + 2 * (*grid)->getNumPoints() * (*grid)->getNumOutputs(), c) : std::copy(cc, cc + (*grid)->getNumPoints() * (*grid)->getNumOutputs(), c); } void tsgshc_(TasmanianSparseGrid **grid, double *c){(*grid)->setHierarchicalCoefficients(c);} void tsghsu_(TasmanianSparseGrid **grid, double *c){ std::vector sup = (*grid)->getHierarchicalSupport(); std::copy(sup.begin(), sup.end(), c); } // setAnisotropic/Surplus/Refinement void tsgsar_(TasmanianSparseGrid **grid, int *type, int *min_growth, int *output, int *opt_flags, const int *llimits){ const int *ll = (opt_flags[0] != 0) ? llimits : nullptr; (*grid)->setAnisotropicRefinement(IO::getDepthTypeInt(*type), *min_growth, *output, ll); } void tsgeac_(TasmanianSparseGrid **grid, int *type, int *output, int *result){ auto coeff = (*grid)->estimateAnisotropicCoefficients(IO::getDepthTypeInt(*type), *output); int num_coeff = (*grid)->getNumDimensions(); if ((*type == 2) || (*type == 4) || (*type == 6)) num_coeff *= 2; for(int i=0; isetSurplusRefinement(*tol, *output, ll); } void tsgshr_(TasmanianSparseGrid **grid, double *tol, int *type, int *opt_flags, int *output, const int *llimits){ int theout = (opt_flags[0] != 0) ? *output : -1; const int *ll = (opt_flags[1] != 0) ? llimits : nullptr; (*grid)->setSurplusRefinement(*tol, IO::getTypeRefinementInt(*type), theout, ll); } void tsgcre_(TasmanianSparseGrid **grid){ (*grid)->clearRefinement(); } void tsgmre_(TasmanianSparseGrid **grid){ (*grid)->mergeRefinement(); } // set/is/clear/getConformalTransform void tsgsca_(TasmanianSparseGrid **grid, int *trunc){ (*grid)->setConformalTransformASIN(Utils::copyArray(trunc, (*grid)->getNumDimensions())); } void tsgica_(TasmanianSparseGrid **grid, int *result){ *result = ((*grid)->isSetConformalTransformASIN()) ? 1 : 0; } void tsgcct_(TasmanianSparseGrid **grid){ (*grid)->clearConformalTransform(); } void tsggca_(TasmanianSparseGrid **grid, int *trunc){ auto truncation_vector = (*grid)->getConformalTransformASIN(); std::copy(truncation_vector.begin(), truncation_vector.end(), trunc); } // isGlobal/Sequence/LocalPolynomial/Wavelet/Fourier void tsgisg_(TasmanianSparseGrid **grid, int *status){*status = ((*grid)->isGlobal()) ? 1 : 0;} void tsgiss_(TasmanianSparseGrid **grid, int *status){*status = ((*grid)->isSequence()) ? 1 : 0;} void tsgisl_(TasmanianSparseGrid **grid, int *status){*status = ((*grid)->isLocalPolynomial()) ? 1 : 0;} void tsgisw_(TasmanianSparseGrid **grid, int *status){*status = ((*grid)->isWavelet()) ? 1 : 0;} void tsgisf_(TasmanianSparseGrid **grid, int *status){*status = ((*grid)->isFourier()) ? 1 : 0;} // print stats void tsgpri_(TasmanianSparseGrid **grid){ (*grid)->printStats(); } // get/enableAcceleration void tsgacc_(TasmanianSparseGrid **grid, int *acc){ (*grid)->enableAcceleration(AccelerationMeta::getIOIntAcceleration(*acc)); } void tsggac_(TasmanianSparseGrid **grid, int *acc){ TypeAcceleration accel = (*grid)->getAccelerationType(); *acc = AccelerationMeta::getIOAccelerationInt(accel); } void tsgsgi_(TasmanianSparseGrid **grid, int *gpuID){ (*grid)->setGPUID(*gpuID); } void tsgggi_(TasmanianSparseGrid **grid, int *gpuID){ *gpuID = (*grid)->getGPUID(); } void tsggng_(int *gpus){ *gpus = TasmanianSparseGrid::getNumGPUs(); } void tsgggm_(int *gpuID, int *mem){ *mem = TasmanianSparseGrid::getGPUMemory(*gpuID); } // MPI send/recv/bcast #ifdef Tasmanian_ENABLE_MPI void tsgmpigsend_(TasmanianSparseGrid **grid, int *dest, int *tag, MPI_Fint *comm, int *ierr){ *ierr = MPIGridSend(**grid, *dest, *tag, MPI_Comm_f2c(*comm)); } void tsgmpigrecv_(TasmanianSparseGrid **grid, int *src, int *tag, MPI_Fint *comm, MPI_Fint *stat, int *ierr){ MPI_Status status; *ierr = MPI_Status_f2c(stat, &status); if (*ierr != MPI_SUCCESS) return; *ierr = MPIGridRecv(**grid, *src, *tag, MPI_Comm_f2c(*comm), &status); } void tsgmpigcast_(TasmanianSparseGrid **grid, int *root, MPI_Fint *comm, int *ierr){ *ierr = MPIGridBcast(**grid, *root, MPI_Comm_f2c(*comm)); } #else void tsgmpigsend_(TasmanianSparseGrid**, int*, int*, int*, int*){} void tsgmpigrecv_(TasmanianSparseGrid**, int*, int*, int*, int*, int*){} void tsgmpigcast_(TasmanianSparseGrid**, int*, int*, int*){} #endif } #endif TASMANIAN-8.1/InterfaceFortran/tsgC2FortranBridge.f90000066400000000000000000000074351470551176200221250ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2017, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== !SUBROUTINE tsgc2fmat(r, c, M) ! USE TasmanianSG, only: tsgReceiveMatrix ! INTEGER, INTENT(IN) :: r, c ! DOUBLE PRECISION, INTENT(IN) :: M(r*c) ! CALL tsgReceiveMatrix(r, c, M) !END SUBROUTINE tsgc2fmat !! ========================================= !SUBROUTINE tsgc2fvec(s, V) ! USE TasmanianSG, only: tsgReceiveVector ! INTEGER, INTENT(IN) :: s ! DOUBLE PRECISION, INTENT(IN) :: V(s) ! CALL tsgReceiveVector(s, V) !END SUBROUTINE tsgc2fvec !! ========================================= !SUBROUTINE tsgc2fdouble(d) ! USE TasmanianSG, only: tsgReceiveScalar ! DOUBLE PRECISION, INTENT(IN) :: d ! CALL tsgReceiveScalar(d) !END SUBROUTINE tsgc2fdouble !! ========================================= !SUBROUTINE tsgc2fint(i) ! USE TasmanianSG, only: tsgReceiveInt ! INTEGER, INTENT(IN) :: i ! CALL tsgReceiveInt(i) !END SUBROUTINE tsgc2fint !! ========================================= ! ========================================= SUBROUTINE tsgc2fstr(l, S) USE TasmanianSG, only: tsgReceiveString IMPLICIT NONE INTEGER, INTENT(IN) :: l CHARACTER, INTENT(IN) :: S(l) CALL tsgReceiveString(l, S) END SUBROUTINE tsgc2fstr ! ========================================= TASMANIAN-8.1/InterfaceMATLAB/000077500000000000000000000000001470551176200154665ustar00rootroot00000000000000TASMANIAN-8.1/InterfaceMATLAB/CMakeLists.txt000066400000000000000000000137301470551176200202320ustar00rootroot00000000000000######################################################################## # MATLAB interface, examples and tests ######################################################################## set(Tasmanian_matlab_source_files tsgCancelRefine.m tsgCleanTempFiles.m tsgCopyGrid.m tsgDeleteGridByName.m tsgDeleteGrid.m tsgDifferentiate.m tsgEstimateAnisotropicCoefficients.m tsgEvaluateHierarchy.m tsgEvaluate.m tsgExample.m tsgGetCandidateConstructionAnisotropic.m tsgGetCandidateConstructionSurplus.m tsgGetHCoefficients.m tsgGetHSupport.m tsgGetInterpolationWeights.m tsgGetDifferentiationWeights.m tsgGetNeededIndexes.m tsgGetNeededPoints.m tsgGetPointsIndexes.m tsgGetPoints.m tsgGetPolynomialSpaces.m tsgGetQuadrature.m tsgIntegrate.m tsgListGridsByName.m tsgLoadConstructedPoints.m tsgLoadGridFromFile.m tsgLoadHCoefficients.m tsgLoadValues.m tsgMakeExoticQuadrature.m tsgMakeFilenames.m tsgMakeFourier.m tsgMakeGlobal.m tsgMakeGridFilename.m tsgMakeLocalPolynomial.m tsgMakeQuadrature.m tsgMakeSequence.m tsgMakeWavelet.m tsgMergeRefine.m tsgPlotPoints2D.m tsgReadCustomRuleFile.m tsgReadMatrix.m tsgRefineAnisotropic.m tsgRefineSurplus.m tsgReloadGrid.m tsgSummary.m tsgUsingConstruction.m tsgCoreTests.m tsgWriteCustomRuleFile.m tsgWriteMatrix.m) # configure_file() command causes update to the entire CMake environment, if the file changes # using copy will copy the files on change but will not reconfigure the environment foreach(Tasmanian_matlab_source_file ${Tasmanian_matlab_source_files}) add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/matlab/${Tasmanian_matlab_source_file}" COMMAND "${CMAKE_COMMAND}" ARGS -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${Tasmanian_matlab_source_file}" "${CMAKE_CURRENT_BINARY_DIR}/matlab/${Tasmanian_matlab_source_file}" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${Tasmanian_matlab_source_file}" COMMENT "Copying ${CMAKE_CURRENT_SOURCE_DIR}/${Tasmanian_matlab_source_file}") list(APPEND Tasmanian_matlab_pre_install_files "${CMAKE_CURRENT_BINARY_DIR}/matlab/${Tasmanian_matlab_source_file}") endforeach() add_custom_target(Tasmanian_matlab_interface ALL DEPENDS "${Tasmanian_matlab_pre_install_files}") # set MATLAB (tasgrid and temp folder) for the build folder (stage 1) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tempMATLAB/") # place for temp files if running matlab from the build location set(Tasmanian_matlab_tasgrid "${CMAKE_CURRENT_BINARY_DIR}/../Tasgrid/tasgrid") string(REPLACE " " "\\ " Tasmanian_matlab_tasgrid "${Tasmanian_matlab_tasgrid}") set(Tasmanian_matlab_workdir "${CMAKE_CURRENT_BINARY_DIR}/tempMATLAB/") string(REPLACE " " "\\ " Tasmanian_matlab_workdir "${Tasmanian_matlab_workdir}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tsgGetPaths.build.m" "${CMAKE_CURRENT_BINARY_DIR}/matlab/tsgGetPaths.m" @ONLY) # set MATLAB (tasgrid and temp folder) for the install folder (stage 2) set(Tasmanian_matlab_tasgrid "${Tasmanian_final_install_path}/bin/tasgrid") string(REPLACE " " "\\ " Tasmanian_matlab_tasgrid "${Tasmanian_matlab_tasgrid}") #message("${Tasmanian_matlab_tasgrid}") # sanity check, especially if spaces are present in folder names set(Tasmanian_matlab_workdir "${Tasmanian_MATLAB_WORK_FOLDER}/") string(REPLACE " " "\\ " Tasmanian_matlab_workdir "${Tasmanian_matlab_workdir}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tsgGetPaths.install.m" "${CMAKE_CURRENT_BINARY_DIR}/configured/tsgGetPaths.m" @ONLY) # test if we can find the octave executable and we can get the version # do not test with MATLAB to avoid potential license issues find_program(Tasmanian_OCTAVE_EXECUABLE NAMES octave) if (Tasmanian_OCTAVE_EXECUABLE) execute_process(COMMAND octave --version OUTPUT_QUIET RESULT_VARIABLE Tasmanian_octave_works) if ("${Tasmanian_octave_works}" STREQUAL 0) add_test(TasmanianOctave octave --eval "addpath('${CMAKE_CURRENT_BINARY_DIR}/matlab'); tsgCoreTests()") endif() endif() # create the MATLAB work-folder on install install(CODE "file(MAKE_DIRECTORY \"${Tasmanian_MATLAB_WORK_FOLDER}\")") # installed files install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" DESTINATION "share/Tasmanian/matlab/" FILES_MATCHING PATTERN "*.m" PATTERN "tsgGetPaths.*" EXCLUDE) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured/tsgGetPaths.m" DESTINATION "share/Tasmanian/matlab/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) TASMANIAN-8.1/InterfaceMATLAB/tsgCancelRefine.m000066400000000000000000000014311470551176200206770ustar00rootroot00000000000000function tsgCancelRefine(lGrid) % % tsgClearRefinement(lGrid) % % clears the last refinement, so long as this is called before % tsgLoadValues(...) % % INPUT: % % lGrid: a grid list created by tsgMake***(...) % % OUTPUT: % % The grid file associated with lGrid is modified % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -cancelrefine']; sCommand = [sCommand, ' -gridfile ', sFileG]; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end end end TASMANIAN-8.1/InterfaceMATLAB/tsgCleanTempFiles.m000066400000000000000000000047351470551176200212260ustar00rootroot00000000000000function tsgCleanTempFiles(lGrid, lFiles) % % tsgCleanTempFiles(lGrid, bFlags) % % Cleans the temporary files associated with lGrid, i.e., all files other % than the _FileG. If lFlags is [], then all files are cleaned. Otherwise % only the files with entries in lFlags are cleaned, this is done to limit % unecessary calls to the 'rm' command. % % You may call this function, but it exists mostly to be called by other % functions. In fact, other functions should clean their temp files so you % should never have to worry about this. % % INPUT: % lGrid: a grid list created by a tsgMake***(...) command (i.e., an % existing grid) % % lFiles: object with fields sFileX, sFileV, sFileO, sFileW, sFileC % corresponding to the files to be deleted. If the field % exist, then the file is deleted. If lFiles is omitted, then % all files are deleted (except the permanent grid file FileG % % generate filenames [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sFileX = regexprep(sFileX, '\\ ', ' '); sFileV = regexprep(sFileV, '\\ ', ' '); sFileO = regexprep(sFileO, '\\ ', ' '); sFileW = regexprep(sFileW, '\\ ', ' '); sFileC = regexprep(sFileC, '\\ ', ' '); sFileL = regexprep(sFileL, '\\ ', ' '); if (isfield(lFiles, 'all')) if (exist(sFileX, 'file') == 2) delete(sFileX); end if (exist(sFileV, 'file') == 2) delete(sFileV); end if (exist(sFileO, 'file') == 2) delete(sFileO); end if (exist(sFileW, 'file') == 2) delete(sFileW); end if (exist(sFileC, 'file') == 2) delete(sFileC); end if (exist(sFileL, 'file') == 2) delete(sFileL); end else if (isfield(lFiles, 'sFileX')) if (exist(sFileX, 'file') == 2) delete(sFileX); end end if (isfield(lFiles, 'sFileV')) if (exist(sFileV, 'file') == 2) delete(sFileV); end end if (isfield(lFiles, 'sFileO')) if (exist(sFileO, 'file') == 2) delete(sFileO); end end if (isfield(lFiles, 'sFileW')) if (exist(sFileW, 'file') == 2) delete(sFileW); end end if (isfield(lFiles, 'sFileC')) if (exist(sFileC, 'file') == 2) delete(sFileC); end end if (isfield(lFiles, 'sFileL')) if (exist(sFileL, 'file') == 2) delete(sFileL); end end end end TASMANIAN-8.1/InterfaceMATLAB/tsgCopyGrid.m000066400000000000000000000022361470551176200201050ustar00rootroot00000000000000function [lNewGrid] = tsgCopyGrid(lOldGrid, sNewGridName) % % [lNewGrid] = tsgCopyGrid(lOldGrid, sNewGridName) % % Makes a physical copy of a grid that differs only in the name % Note: tsgCopyGrid will create a new grid file in the work folder, while % the command lNewGrid = lOldGrid will only create an alias % % INPUT: % % lGrid: a grid list created by tsgMake***(...) % % sNewGridName: the name for the new grid, the new grid will be identical % to the old one in every other way % % OUTPUT: % % lNewGrid: a grid object pointing to the physical copy of the old grid % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lOldGrid); lNewGrid = lOldGrid; lNewGrid.sName = sNewGridName; if isfield(lNewGrid, 'sFilename') lNewGrid.sFilename = tsgMakeGridFilename(sNewGridName); end [sFileGNew, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lNewGrid); sFileG = regexprep(sFileG, '\\ ', ' '); sFileGNew = regexprep(sFileGNew, '\\ ', ' '); [status, cmdout] = copyfile(sFileG, sFileGNew); if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end end TASMANIAN-8.1/InterfaceMATLAB/tsgCoreTests.m000066400000000000000000001316761470551176200203130ustar00rootroot00000000000000function tsgCoreTests() disp(['']); disp(['Testing TASMANIAN MATLAB interface']); [sFiles, sTasGrid] = tsgGetPaths(); disp(['Tasmanian executable: ']); disp([' ',sTasGrid]); disp(['Tasmanian work folder:']); disp([' ', sFiles]); disp(['']); [status, cmdout] = system([sTasGrid, ' -v']); if (status ~= 0) disp(cmdout); error('There was an error while executing tasgrid.'); end disp(cmdout); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgMakeQuadrature() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Basic quadrature calls and check for correct points and weight [weights, points] = tsgMakeQuadrature(2, 'clenshaw-curtis', 'level', 1, 0); tw = [4.0/3.0, 2.0/3.0, 2.0/3.0, 2.0/3.0, 2.0/3.0]'; tp = [0.0, 0.0; 0.0, -1.0; 0.0, 1.0; -1.0, 0.0; 1.0, 0.0; ]; if ((norm(tw - weights) > 1.E-11) || (norm(tp - points) > 1.E-11)) error('Mismatch in points and weights of simple quadrature 1'); end [weights, points] = tsgMakeQuadrature(2, 'clenshaw-curtis', 'level', 2, 0); if ((norm(points(4,2) + 1.0 / sqrt(2.0)) > 1.E-11) || (norm(points(5,2) - 1.0 / sqrt(2.0)) > 1.E-11) ... || (norm(weights(7) - 1.0 / 9.0) > 1.E-11)) error('Mismatch in points and weights of simple quadrature 2'); end [weights, points] = tsgMakeQuadrature(3, 'fejer2', 'level', 4, 0); if ((norm(sum(weights) - 2.0^3) > 1.E-11) || (abs(sum(sum(points))) > 1.E-11)) error('Mismatch in points and weights of simple quadrature 3'); end [weights, points] = tsgMakeQuadrature(1, 'leja', 'level', 3, 0); tw = [4.0/3.0, 1.0/3.0, 1.0/3.0, 0.0]'; tp = [0.0, 1.0, -1.0, sqrt(1.0/3.0)]'; if ((norm(tw - weights) > 1.E-11) || (norm(tp - points) > 1.E-11)) error('Mismatch in points and weights of simple quadrature 4'); end % test transform [w, p] = tsgMakeQuadrature(3, 'clenshaw-curtis', 'level', 2, 0, [3.0 5.0; -7.0 -6.0; -12.0 17.0]); if ((abs(norm(sum(w)) - 58.0) > 1.E-11) || (abs(max(p(:, 1)) - 5.0) > 1.E-11) ... || (abs(min(p(:, 1)) - 3.0) > 1.E-11) || (abs(max(p(:, 2)) + 6.0) > 1.E-11) ... || (abs(min(p(:, 2)) + 7.0) > 1.E-11) || (abs(max(p(:, 3)) - 17.0) > 1.E-11) ... || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in points and weights of simple quadrature: transform'); end % test alpha/beta [w, p] = tsgMakeQuadrature(1, 'gauss-hermite', 'level', 4, 0, [], [2.0;]); if (abs(norm(sum(w)) - 0.5 * pi^0.5) > 1.E-11) error('Mismatch in points and weights of simple quadrature: alpha/beta'); end % test anisotropy [w, p] = tsgMakeQuadrature(2, 'leja', 'level', 2, 0, [], [], [2, 1]'); tp = [0.0 0.0; 0.0 1.0; 0.0 -1.0; 1.0 0.0;]; if ((abs(sum(w) - 4.0) > 1.E-11) || (norm(p - tp) > 1.E-11)) error('Mismatch in points and weights of simple quadrature: anisotropy'); end % test custom rule vNodes = []; vWeights = []; for iL = 0:4 [w, p] = tsgMakeQuadrature(1, 'gauss-legendre', 'level', iL, -1); vNodes = [vNodes; p]; vWeights = [vWeights; w]; end lCustomRule.sDescription = 'Test Gauss-Legendre'; lCustomRule.iMaxLevel = 5; lCustomRule.vLevels = 1:5; lCustomRule.vPrecision = 2 * lCustomRule.vLevels - 1; lCustomRule.vNodes = vNodes; lCustomRule.vWeights = vWeights; [tw, tp] = tsgMakeQuadrature(2, 'gauss-legendre', 'level', 3, 0, [], [], [2, 1]'); [w, p] = tsgMakeQuadrature(2, 'custom-tabulated', 'level', 3, 0, [], [], [2, 1]', lCustomRule); if ((norm(tw - w) > 1.E-11) || (norm(tp - p) > 1.E-11)) error('Mismatch in points and weights of simple quadrature: custom rule'); end % test conformal for iL = 7:8 [w, p] = tsgMakeQuadrature(2, 'gauss-patterson', 'qptotal', iL, -1); [wc, pc] = tsgMakeQuadrature(2, 'gauss-patterson', 'qptotal', iL, -1, [], [], [], [], 'asin', [4, 4]); I = sum(w .* (1.0 ./ ((1.0 + 5.0 .* p(:,1).^2) .* (1.0 + 5.0 .* p(:,2).^2)))); Ic = sum(wc .* (1.0 ./ ((1.0 + 5.0 .* pc(:,1).^2) .* (1.0 + 5.0 .* pc(:,2).^2)))); %[abs(I - 1.028825601981092^2), abs(Ic - 1.028825601981092^2)] if (abs(I - 1.028825601981092^2) < abs(Ic - 1.028825601981092^2)) error('Mismatch in points and weights of simple quadrature: conformal map'); end end % test level limits [w, p] = tsgMakeQuadrature(2, 'clenshaw-curtis', 'qptotal', 20, -1, [], [], [], [], [], [], [1, 3]); [tw, tp] = tsgMakeQuadrature(2, 'clenshaw-curtis', 'tensor', 1, -1, [], [], [1, 3], [], [], [], []); % when the limitation of iDepth far exceeds the level limits, the grid converges to a full tensor grid if (abs(sum(w) - 4.0) > 1.E-11) error('Mismatch in points and weights of simple quadrature: level limit, sum of weights'); end if ((norm(w - tw) > 1.E-11) || (norm(p - tp) > 1.E-11)) error('Mismatch in points and weights of simple quadrature: level limit, points and weights'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgMakeExoticQuadrature() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Create a sinc function surrogate. [lWeightGrid, points] = tsgMakeGlobal('Sinc_Surrogate', 1, 1, 'gauss-legendre', 'qptotal', 200); vals = zeros(length(points), 1); for i=1:length(points) if abs(points(i)) <= 1e-16 vals(i) = 1.0; else vals(i) = sin(points(i)) / points(i); end end tsgLoadValues(lWeightGrid, vals); % Create the exotic quadrature rule and test it on 1D and 2D instances. iDepth = 40; lCustomRule = tsgMakeExoticQuadrature(iDepth, 1.0, lWeightGrid, 'Sinc_Exoquad', true); [w1, p1] = tsgMakeQuadrature(1, 'custom-tabulated', 'qptotal', iDepth, 0, [], [], [], lCustomRule); I1 = sum(w1 .* exp(-p1 .* p1)); if (abs(I1 - 1.4321357541271255) > 1E-11) error('Mismatch in generated sinc-weighted integral of tsgMakeExoticQuadrature() for dimension 1'); end [w2, p2] = tsgMakeQuadrature(2, 'custom-tabulated', 'qptotal', iDepth, 0, [], [], [], lCustomRule); I2 = sum(w2 .* exp(-p2(:, 1) .* p2(:, 1) - p2(:, 2) .* p2(:, 2))); if (abs(I2 - 1.4321357541271255 ^ 2) > 1E-11) error('Mismatch in generated sinc-weighted integral of tsgMakeExoticQuadrature() for dimension 2'); end % Clean up tsgDeleteGrid(lWeightGrid) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgMakeGlobal() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 1, 'clenshaw-curtis', 'level', 1); tp = [0.0, 0.0; 0.0, -1.0; 0.0, 1.0; -1.0, 0.0; 1.0, 0.0;]; if (norm(tp - p) > 1.E-11) error('Mismatch in tsgMakeGlobal: core case 1'); end % test transform [lGrid, p] = tsgMakeGlobal('_tsgcoretests_lgrid', 3, 1, 'clenshaw-curtis', 'level', 2, [3.0 5.0; -7.0 -6.0; -12.0 17.0]); if ((abs(max(p(:, 1)) - 5.0) > 1.E-11) || (abs(min(p(:, 1)) - 3.0) > 1.E-11) ... || (abs(max(p(:, 2)) + 6.0) > 1.E-11) || (abs(min(p(:, 2)) + 7.0) > 1.E-11) ... || (abs(max(p(:, 3)) - 17.0) > 1.E-11) || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeGlobal: transform'); end [w, p] = tsgGetQuadrature(lGrid); if ((abs(norm(sum(w)) - 58.0) > 1.E-11) || (abs(max(p(:, 1)) - 5.0) > 1.E-11) ... || (abs(min(p(:, 1)) - 3.0) > 1.E-11) || (abs(max(p(:, 2)) + 6.0) > 1.E-11) ... || (abs(min(p(:, 2)) + 7.0) > 1.E-11) || (abs(max(p(:, 3)) - 17.0) > 1.E-11) ... || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeGlobal: getQuadrature'); end % test alpha/beta [lGrid] = tsgMakeGlobal('_tsgcoretests_lgrid', 1, 1, 'gauss-hermite', 'level', 4, [], [2.0;]); [w, p] = tsgGetQuadrature(lGrid); if (abs(norm(sum(w)) - 0.5 * pi^0.5) > 1.E-11) error('Mismatch in tsgMakeGlobal: alpha/beta'); end % test anisotropy [lGrid] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 1, 'leja', 'level', 2, [], [], [2, 1]); w = []; p = []; [w, p] = tsgGetQuadrature(lGrid); tp = [0.0 0.0; 0.0 1.0; 0.0 -1.0; 1.0 0.0;]; if ((abs(sum(w) - 4.0) > 1.E-11) || (norm(p - tp) > 1.E-11)) error('Mismatch in tsgMakeGlobal: anisotropy'); end [lGrid] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 1, 'leja', 'level', 2, [], [], [2, 1]'); w = []; p = []; [w, p] = tsgGetQuadrature(lGrid); tp = [0.0 0.0; 0.0 1.0; 0.0 -1.0; 1.0 0.0;]; if ((abs(sum(w) - 4.0) > 1.E-11) || (norm(p - tp) > 1.E-11)) error('Mismatch in tsgMakeGlobal: anisotropy'); end % test custom rule vNodes = []; vWeights = []; for iL = 0:4 [w, p] = tsgMakeQuadrature(1, 'gauss-legendre', 'level', iL, -1); vNodes = [vNodes; p]; vWeights = [vWeights; w]; end lCustomRule.sDescription = 'Test Gauss-Legendre'; lCustomRule.iMaxLevel = 5; lCustomRule.vLevels = 1:5; lCustomRule.vPrecision = 2 * lCustomRule.vLevels - 1; lCustomRule.vNodes = vNodes; lCustomRule.vWeights = vWeights; [tw, tp] = tsgMakeQuadrature(2, 'gauss-legendre', 'level', 3, 0, [], [], [2, 1]'); [lGrid] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 1, 'custom-tabulated', 'level', 3, [], [], [2, 1]', lCustomRule); w = []; p = []; [w, p] = tsgGetQuadrature(lGrid); if ((norm(tw - w) > 1.E-11) || (norm(tp - p) > 1.E-11)) error('Mismatch in tsgMakeGlobal: custom rule'); end % test conformal pnts = [-1.0 + 2.0 * rand(100, 2)]; tres = 1.0 ./ ((1.0 + 5.0 .* pnts(:,1).^2) .* (1.0 + 5.0 .* pnts(:,2).^2)); for iL = 7:8 [lGrid, p] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 1, 'clenshaw-curtis', 'iptotal', iL, [], [], [], [], 'asin', [4, 4]); n1 = size(p, 1); v = 1.0 ./ ((1.0 + 5.0 .* p(:,1).^2) .* (1.0 + 5.0 .* p(:,2).^2)); tsgLoadValues(lGrid, v); [resc] = tsgEvaluate(lGrid, pnts); p = []; [lGrid, p] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 1, 'clenshaw-curtis', 'iptotal', iL); v = 1.0 ./ ((1.0 + 5.0 .* p(:,1).^2) .* (1.0 + 5.0 .* p(:,2).^2)); tsgLoadValues(lGrid, v); [resn] = tsgEvaluate(lGrid, pnts); if (size(p, 1) ~= n1) error('Mismatch in tsgMakeGlobal: conformal number of points'); end if (norm(tres - resc) > norm(tres - resn)) error('Mismatch in tsgMakeGlobal: conformal error'); end end % test level limits [lGrid, p1] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 1, 'clenshaw-curtis', 'iptotal', 20, [], [], [], [], [], [], [1, 3]); [lGrid, p2] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 1, 'clenshaw-curtis', 'tensor', 1, [], [], [1, 3]); if (norm(p1 - p2) > 1.E-11) error('Mismatch in tsgMakeGlobal: level limits'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgDeleteGrid() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [sFiles, sTasGrid] = tsgGetPaths(); sFiles = regexprep(sFiles, '\\ ', ' '); if (~exist([sFiles,'_tsgcoretests_lgrid.tsgrid'], 'file')) error('Mismatch in tsgDeleteGrid: cannot find a file that should exist'); end tsgDeleteGrid(lGrid); if (exist([sFiles,'_tsgcoretests_lgrid.tsgrid'], 'file')) error('Mismatch in tsgDeleteGrid: did not delete the file'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgCopyGrid() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGridA, p] = tsgMakeGlobal('_tsgcoretests_lgridA', 2, 1, 'clenshaw-curtis', 'iptotal', 3, [], [], [], [], 'asin', [4, 4]); [lGridB] = tsgCopyGrid(lGridA, '_tsgcoretests_lgridB'); tsgDeleteGrid(lGridA); [p2] = tsgGetPoints(lGridB); if (norm(p - p2) > 1.E-11) error('Mismatch in tsgCopyGrid: did not get the correct points'); end tsgDeleteGrid(lGridB); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgMakeSequence() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeSequence('_tsgcoretests_lgrid2', 2, 1, 'min-lebesgue', 'level', 3); tp = [0.0, 0.0; 0.0, 1.0; 0.0, -1.0; 0.0, sqrt(1.0/3.0); 1.0, 0.0; 1.0, 1.0; 1.0, -1.0; -1.0, 0.0; -1.0, 1.0; sqrt(1.0/3.0), 0.0;]; if (norm(tp - p) > 1.E-11) error('Mismatch in tsgMakeSequence: core case 1'); end % test transform [lGrid, p] = tsgMakeSequence('_tsgcoretests_lgrid2', 3, 1, 'rleja', 'level', 2, [3.0 5.0; -7.0 -6.0; -12.0 17.0]); if ((abs(max(p(:, 1)) - 5.0) > 1.E-11) || (abs(min(p(:, 1)) - 3.0) > 1.E-11) ... || (abs(max(p(:, 2)) + 6.0) > 1.E-11) || (abs(min(p(:, 2)) + 7.0) > 1.E-11) ... || (abs(max(p(:, 3)) - 17.0) > 1.E-11) || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeSequence: transform'); end [w, p] = tsgGetQuadrature(lGrid); if ((abs(norm(sum(w)) - 58.0) > 1.E-11) || (abs(max(p(:, 1)) - 5.0) > 1.E-11) ... || (abs(min(p(:, 1)) - 3.0) > 1.E-11) || (abs(max(p(:, 2)) + 6.0) > 1.E-11) ... || (abs(min(p(:, 2)) + 7.0) > 1.E-11) || (abs(max(p(:, 3)) - 17.0) > 1.E-11) ... || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeSequence: getQuadrature'); end % test anisotropy [lGrid] = tsgMakeSequence('_tsgcoretests_lgrid2', 2, 1, 'leja', 'level', 2, [], [2, 1]); w = []; p = []; [w, p] = tsgGetQuadrature(lGrid); tp = [0.0 0.0; 0.0 1.0; 0.0 -1.0; 1.0 0.0;]; if ((abs(sum(w) - 4.0) > 1.E-11) || (norm(p - tp) > 1.E-11)) error('Mismatch in tsgMakeSequence: anisotropy'); end [lGrid] = tsgMakeSequence('_tsgcoretests_lgrid2', 2, 1, 'leja', 'level', 2, [], [2, 1]'); w = []; p = []; [w, p] = tsgGetQuadrature(lGrid); tp = [0.0 0.0; 0.0 1.0; 0.0 -1.0; 1.0 0.0;]; if ((abs(sum(w) - 4.0) > 1.E-11) || (norm(p - tp) > 1.E-11)) error('Mismatch in tsgMakeSequence: anisotropy'); end % test conformal pnts = [-1.0 + 2.0 * rand(100, 2)]; tres = 1.0 ./ ((1.0 + 5.0 .* pnts(:,1).^2) .* (1.0 + 5.0 .* pnts(:,2).^2)); for iL = 7:8 [lGrid, p] = tsgMakeSequence('_tsgcoretests_lgrid', 2, 1, 'rleja', 'iptotal', iL, [], [], 'asin', [4, 4]); n1 = size(p, 1); v = 1.0 ./ ((1.0 + 5.0 .* p(:,1).^2) .* (1.0 + 5.0 .* p(:,2).^2)); tsgLoadValues(lGrid, v); [resc] = tsgEvaluate(lGrid, pnts); p = []; [lGrid, p] = tsgMakeSequence('_tsgcoretests_lgrid', 2, 1, 'rleja', 'iptotal', iL); v = 1.0 ./ ((1.0 + 5.0 .* p(:,1).^2) .* (1.0 + 5.0 .* p(:,2).^2)); tsgLoadValues(lGrid, v); [resn] = tsgEvaluate(lGrid, pnts); if (size(p, 1) ~= n1) error('Mismatch in tsgMakeSequence: conformal number of points'); end if (norm(tres - resc) > norm(tres - resn)) error('Mismatch in tsgMakeSequence: conformal error'); end end % test level limits [lGrid, p1] = tsgMakeSequence('_tsgcoretests_lgrid', 2, 1, 'min-delta', 'iptotal', 20, [], [], [], [], [1, 3]); [lGrid, p2] = tsgMakeSequence('_tsgcoretests_lgrid', 2, 1, 'min-delta', 'tensor', 1, [], [1, 3]); if (norm(p1 - p2) > 1.E-11) error('Mismatch in tsgMakeSequence: level limits'); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgDeleteGridByName() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [sFiles, sTasGrid] = tsgGetPaths(); sFiles = regexprep(sFiles, '\\ ', ' '); if (~exist([sFiles,'_tsgcoretests_lgrid2.tsgrid'], 'file')) error('Mismatch in tsgDeleteGrid: cannot find a file that should exist'); end tsgDeleteGridByName('_tsgcoretests_lgrid2'); if (exist([sFiles,'_tsgcoretests_lgrid2.tsgrid'], 'file')) error('Mismatch in tsgDeleteGrid: did not delete the file'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgMakeLocalPolynomial() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % test transform [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lgrid2', 3, 1, 'localp', 2, 2, [3.0 5.0; -7.0 -6.0; -12.0 17.0]); if ((abs(max(p(:, 1)) - 5.0) > 1.E-11) || (abs(min(p(:, 1)) - 3.0) > 1.E-11) ... || (abs(max(p(:, 2)) + 6.0) > 1.E-11) || (abs(min(p(:, 2)) + 7.0) > 1.E-11) ... || (abs(max(p(:, 3)) - 17.0) > 1.E-11) || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeLocalPolynomial: transform'); end [w, p] = tsgGetQuadrature(lGrid); if ((abs(norm(sum(w)) - 58.0) > 1.E-11) || (abs(max(p(:, 1)) - 5.0) > 1.E-11) ... || (abs(min(p(:, 1)) - 3.0) > 1.E-11) || (abs(max(p(:, 2)) + 6.0) > 1.E-11) ... || (abs(min(p(:, 2)) + 7.0) > 1.E-11) || (abs(max(p(:, 3)) - 17.0) > 1.E-11) ... || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeLocalPolynomial: getQuadrature'); end tsgDeleteGrid(lGrid); % test conformal pnts = [-1.0 + 2.0 * rand(100, 2)]; tres = 1.0 ./ ((1.0 + 5.0 .* pnts(:,1).^2) .* (1.0 + 5.0 .* pnts(:,2).^2)); for iL = 3:4 [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lgrid', 2, 1, 'semi-localp', iL, 2, [], 'asin', [4, 4]); n1 = size(p, 1); v = 1.0 ./ ((1.0 + 5.0 .* p(:,1).^2) .* (1.0 + 5.0 .* p(:,2).^2)); tsgLoadValues(lGrid, v); [resc] = tsgEvaluate(lGrid, pnts); p = []; [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lgrid', 2, 1, 'semi-localp', iL, 2); v = 1.0 ./ ((1.0 + 5.0 .* p(:,1).^2) .* (1.0 + 5.0 .* p(:,2).^2)); tsgLoadValues(lGrid, v); [resn] = tsgEvaluate(lGrid, pnts); if (size(p, 1) ~= n1) error('Mismatch in tsgMakeLocalPolynomial: conformal number of points'); end if (norm(tres - resc) > norm(tres - resn)) error('Mismatch in tsgMakeLocalPolynomial: conformal error'); end end tsgDeleteGrid(lGrid); % polynomial order is tested in tsgEvaluate() % level limits [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lgrid', 3, 1, 'semi-localp', 3, 2, [], [], [], [1, 2, 3]); if (min(abs(p(:,1) - 0.5)) < 1.E-8) error('Mismatch in tsgMakeLocalPolynomial: level limit, dim 1'); end if (min(abs(p(:,2) - 0.75)) < 1.E-8) error('Mismatch in tsgMakeLocalPolynomial: level limit, dim 2'); end if (min(abs(p(:,3) - 0.125)) < 1.E-8) error('Mismatch in tsgMakeLocalPolynomial: level limit, dim 3'); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgMakeWavelet() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % test transform [lGrid, p] = tsgMakeWavelet('_tsgcoretests_lgrid', 3, 1, 2, 1, [3.0 5.0; -7.0 -6.0; -12.0 17.0]); if ((abs(max(p(:, 1)) - 5.0) > 1.E-11) || (abs(min(p(:, 1)) - 3.0) > 1.E-11) ... || (abs(max(p(:, 2)) + 6.0) > 1.E-11) || (abs(min(p(:, 2)) + 7.0) > 1.E-11) ... || (abs(max(p(:, 3)) - 17.0) > 1.E-11) || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeWavelet: transform'); end [w, p] = tsgGetQuadrature(lGrid); if ((abs(norm(sum(w)) - 58.0) > 1.E-11) || (abs(max(p(:, 1)) - 5.0) > 1.E-11) ... || (abs(min(p(:, 1)) - 3.0) > 1.E-11) || (abs(max(p(:, 2)) + 6.0) > 1.E-11) ... || (abs(min(p(:, 2)) + 7.0) > 1.E-11) || (abs(max(p(:, 3)) - 17.0) > 1.E-11) ... || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeWavelet: getQuadrature'); end % correctness of 1-D [lGrid, pw] = tsgMakeWavelet('_tsgcoretests_lgrid', 1, 1, 2, 1); [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lgrid', 1, 1, 'localp', 3, 1); if (norm(pw - p) > 1.E-11) error('Mismatch in tsgMakeWavelet: points'); end % test conformal for iL = 3:4 [lGrid, p] = tsgMakeWavelet('_tsgcoretests_lgrid', 2, 1, iL, 1, [], 'asin', [4, 4]); [w, p] = tsgGetQuadrature(lGrid); [lGrid, p] = tsgMakeWavelet('_tsgcoretests_lgrid', 2, 1, iL, 1); [wc, pc] = tsgGetQuadrature(lGrid); I = sum(w .* (1.0 ./ ((1.0 + 5.0 .* p(:,1).^2) .* (1.0 + 5.0 .* p(:,2).^2)))); Ic = sum(wc .* (1.0 ./ ((1.0 + 5.0 .* pc(:,1).^2) .* (1.0 + 5.0 .* pc(:,2).^2)))); if (abs(I - 1.028825601981092^2) < abs(Ic - 1.028825601981092^2)) error('Mismatch in points and weights of simple quadrature: conformal map'); end end tsgDeleteGrid(lGrid); % level limits [lGrid, p] = tsgMakeWavelet('_tsgcoretests_lgrid', 3, 1, 2, 1, [], [], [], [0, 1, 2]); if (min(abs(p(:,1) - 0.5)) < 1.E-8) error('Mismatch in tsgMakeLocalPolynomial: level limit, dim 1'); end if (min(abs(p(:,2) - 0.75)) < 1.E-8) error('Mismatch in tsgMakeLocalPolynomial: level limit, dim 2'); end if (min(abs(p(:,3) - 0.125)) < 1.E-8) error('Mismatch in tsgMakeLocalPolynomial: level limit, dim 3'); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgMakeFourier() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % test transform [lGrid, p] = tsgMakeFourier('_tsgcoretests_lgrid', 3, 1, 'level', 1, [3.0 5.0; -7.0 -6.0; -12.0 17.0]); if ((abs(max(p(:, 1)) - 13.0/3.0) > 1.E-11) || (abs(min(p(:, 1)) - 3.0) > 1.E-11) ... || (abs(max(p(:, 2)) + 19.0/3.0) > 1.E-11) || (abs(min(p(:, 2)) + 7.0) > 1.E-11) ... || (abs(max(p(:, 3)) - 22.0/3.0) > 1.E-11) || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeFourier: transform'); end [w, p] = tsgGetQuadrature(lGrid); if ((abs(norm(sum(w)) - 58.0) > 1.E-11) || (abs(max(p(:, 1)) - 13.0/3.0) > 1.E-11) ... || (abs(min(p(:, 1)) - 3.0) > 1.E-11) || (abs(max(p(:, 2)) + 19.0/3.0) > 1.E-11) ... || (abs(min(p(:, 2)) + 7.0) > 1.E-11) || (abs(max(p(:, 3)) - 22.0/3.0) > 1.E-11) ... || (abs(min(p(:, 3)) + 12.0) > 1.E-11)) error('Mismatch in tsgMakeFourier: getQuadrature'); end % correctness of 1-D [lGrid, p] = tsgMakeFourier('_tsgcoretests_lgrid', 1, 1, 'level', 2); tp = [0.0; 1.0/3.0; 2.0/3.0; 1.0/9.0; 2.0/9.0; 4.0/9.0; 5.0/9.0; 7.0/9.0; 8.0/9.0]; if (norm(p - tp) > 1.E-11) error('Mismatch in tsgMakeFourier: points'); end % level limits [lGrid, p] = tsgMakeFourier('_tsgcoretests_lgrid', 3, 1, 'level', 3, [], [], [], [], [0, 1, 2]); if (max(abs(p(:,1))) > 1.E-8) error('Mismatch in tsgMakeFourier: level limit, dim 1'); end if (min(abs(p(:,2) - 1.0/9.0)) < 1.E-8) error('Mismatch in tsgMakeFourier: level limit, dim 2'); end if (min(abs(p(:,3) - 1.0/27.0)) < 1.E-8) error('Mismatch in tsgMakeFourier: level limit, dim 3'); end tsgDeleteGrid(lGrid); disp(['tsgMake* functions PASS']); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgGetPoints() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 1, 'clenshaw-curtis', 'level', 1); tp = [0.0, 0.0; 0.0, -1.0; 0.0, 1.0; -1.0, 0.0; 1.0, 0.0;]; p = []; [p] = tsgGetPoints(lGrid); if (norm(tp - p) > 1.E-11) error('Mismatch in tsgGetPoints: core case 1'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgGetNeededPoints() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% covered in tsgLoadValues() and tsgRefine*() %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgGetQuadrature() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% covered in tsgMakeGlobal() and tsgMakeSequence() %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgLoadValues() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeGlobal('_tsgcoretests_lgrid', 2, 2, 'min-delta', 'level', 4); [pn] = tsgGetNeededPoints(lGrid); if (norm(p - pn) > 1.E-11) error('Mismatch in tsgLoadValues: tsgGetNeededPoints case 1'); end v = [exp(-p(:,1).^2 -p(:,2).^2), cos(-p(:,1) -2.0 * p(:,2))]; tsgLoadValues(lGrid, v); [pn] = tsgGetPoints(lGrid); if (norm(p - pn) > 1.E-11) error('Mismatch in tsgLoadValues: tsgGetPoints'); end [pn] = tsgGetNeededPoints(lGrid); if (max(size(pn)) ~= 0) error('Mismatch in tsgLoadValues: tsgGetNeededPoints case 2'); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgEvaluate() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lp', 2, 4, 'localp', 1, 1); v = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2 + p(:,1).*p(:,2), ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; tsgLoadValues(lGrid, v); p = [1.0/3.0, 1.0/3.0; pi/6.0, -sqrt(2.0)/2.0;]; tv = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2 + p(:,1).*p(:,2), ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; [res] = tsgEvaluate(lGrid, p); for i = 1:2 if (norm(res(:,i) - tv(:,i)) > 1.E-11) error(['Mismatch in tsgEvaluate: case 1, output ',num2str(i)]); end end for i = 3:4 if (norm(res(:,i) - tv(:,i)) < 1.E-8) error(['Mismatch in tsgEvaluate: case 1, output ',num2str(i)]); end end [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lp', 2, 4, 'localp', 1, 2); v = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2 + p(:,1).*p(:,2), ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; tsgLoadValues(lGrid, v); p = [1.0/3.0, 1.0/3.0; pi/6.0, -sqrt(2.0)/2.0;]; tv = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2 + p(:,1).*p(:,2), ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; [res] = tsgEvaluate(lGrid, p); for i = 1:2 if (norm(res(:,i) - tv(:,i)) > 1.E-11) error(['Mismatch in tsgEvaluate: case 2, output ',num2str(i)]); end end for i = 3:4 if (norm(res(:,i) - tv(:,i)) < 1.E-8) error(['Mismatch in tsgEvaluate: case 2, output ',num2str(i)]); end end [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lp', 2, 4, 'semi-localp', 1, 2); v = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2, ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; tsgLoadValues(lGrid, v); p = [1.0/3.0, 1.0/3.0; pi/6.0, -sqrt(2.0)/2.0;]; tv = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2, ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; [res] = tsgEvaluate(lGrid, p); for i = 1:3 if (norm(res(:,i) - tv(:,i)) > 1.E-11) error(['Mismatch in tsgEvaluate: case 3, output ',num2str(i)]); end end for i = 4:4 if (norm(res(:,i) - tv(:,i)) < 1.E-8) error(['Mismatch in tsgEvaluate: case 3, output ',num2str(i)]); end end [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lp', 2, 4, 'localp', 2, 2); v = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2 + p(:,1).*p(:,2), ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; tsgLoadValues(lGrid, v); p = [1.0/3.0, 1.0/3.0; pi/6.0, -sqrt(2.0)/2.0;]; tv = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2 + p(:,1).*p(:,2), ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; [res] = tsgEvaluate(lGrid, p); for i = 1:3 if (norm(res(:,i) - tv(:,i)) > 1.E-11) error(['Mismatch in tsgEvaluate: case 4, output ',num2str(i)]); end end for i = 4:4 if (norm(res(:,i) - tv(:,i)) < 1.E-8) error(['Mismatch in tsgEvaluate: case 4, output ',num2str(i)]); end end [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_lp', 2, 4, 'localp', 3, 3); v = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2 + p(:,1).*p(:,2), ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; tsgLoadValues(lGrid, v); p = [1.0/3.0, 1.0/3.0; pi/6.0, -sqrt(2.0)/2.0;]; tv = [0.3*ones(size(p,1), 1), p(:,1) + p(:,2), ... p(:,1).^2 + p(:,2).^2 + p(:,1).*p(:,2), ... p(:,1).^3 + p(:,2).^3 + p(:,1).*(p(:,2).^2) ]; [res] = tsgEvaluate(lGrid, p); for i = 1:4 if (norm(res(:,i) - tv(:,i)) > 1.E-11) error(['Mismatch in tsgEvaluate: case 5, output ',num2str(i)]); end end tsgDeleteGrid(lGrid); [lGrid, p] = tsgMakeGlobal('_tsgcoretests_ch', 2, 1, 'chebyshev', 'iptotal', 22); v = [exp(-p(:,1).^2 -p(:,2).^2)]; tsgLoadValues(lGrid, v); p = [-1.0 + 2.0 * rand(1000,2)]; v = [exp(-p(:,1).^2 -p(:,2).^2)]; [res] = tsgEvaluate(lGrid, p); if (norm(v - res) > 1.E-9) error(['Mismatch in tsgEvaluate: global grid with chebyshev points']); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgEvaluateHierarchy() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeGlobal('_tsgcoretests_ml', 3, 1, 'fejer2', 'level', 4); [V] = tsgEvaluateHierarchy(lGrid, p); if (norm(V - eye(size(p,1))) > 1.E-11) error(['Mismatch in tsgEvaluateHierarchy: lagrange polynomials do not form identity']); end [lGrid, p] = tsgMakeSequence('_tsgcoretests_ml', 2, 1, 'leja', 'level', 2); pnts = [0.33, 0.25; -0.27, 0.39; 0.97, -0.76; -0.44, 0.21; -0.813, 0.03; -0.666, 0.666]; tres = [ones(size(pnts, 1), 1), pnts(:,2), 0.5 * pnts(:,2) .* (pnts(:,2) - 1.0), pnts(:,1), pnts(:,1) .* pnts(:,2), 0.5 * pnts(:,1) .* (pnts(:,1) - 1.0)]; [res] = tsgEvaluateHierarchy(lGrid, pnts); if (norm(res - tres) > 1.E-11) error(['Mismatch in tsgEvaluateHierarchy: sequence grid test']); end [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_ml', 2, 1, 'localp', 4, 1); v = [exp(-p(:,1).^2 - 2.0 * p(:,2).^2)]; tsgLoadValues(lGrid, v); pnts = [-1.0 + 2.0 * rand(13, 2)]; [tres] = tsgEvaluate(lGrid, pnts); [mVan] = tsgEvaluateHierarchy(lGrid, pnts); [coef] = tsgGetHCoefficients(lGrid); res = mVan * coef; if (norm(tres - res) > 1.E-11) error(['Mismatch in tsgEvaluateHierarchy: localp grid test']); end % this tests reading a complex matrix [lGrid, p] = tsgMakeFourier('_tsgcoretests_ml', 2, 1, 'level', 4); v = [exp(-p(:,1).^2 - 2.0 * p(:,2).^2)]; tsgLoadValues(lGrid, v); pnts = [-1.0 + 2.0 * rand(13, 2)]; [tres] = tsgEvaluate(lGrid, pnts); [mVan] = tsgEvaluateHierarchy(lGrid, pnts); [coef] = tsgGetHCoefficients(lGrid); res = real(mVan * coef); if (norm(tres - res) > 1.E-11) error(['Mismatch in tsgEvaluateHierarchy: Fourier grid test']); end tsgDeleteGrid(lGrid); [lGridA, p] = tsgMakeLocalPolynomial('_tsgcoretests_mlA', 2, 1, 'semi-localp', 5, 1); [lGridB, p] = tsgMakeLocalPolynomial('_tsgcoretests_mlB', 2, 1, 'semi-localp', 5, 1); v = [exp(-p(:,1).^2 - 2.0 * p(:,2).^2)]; tsgLoadValues(lGridA, v); [mVan] = tsgEvaluateHierarchy(lGridB, p); Coeff = mVan \ v; tsgLoadHCoefficients(lGridB, Coeff); pnts = [-1.0 + 2.0 * rand(13, 2)]; [tres] = tsgEvaluate(lGridA, pnts); [res] = tsgEvaluate(lGridB, pnts); if (norm(tres - res) > 1.E-11) error(['Mismatch in tsgEvaluateHierarchy: localp grid solve']); end [lGridA, p] = tsgMakeLocalPolynomial('_tsgcoretests_mlA', 2, 1, 'semi-localp', 5, 1, [-1 2; 7 9;]); [lGridB, p] = tsgMakeLocalPolynomial('_tsgcoretests_mlB', 2, 1, 'semi-localp', 5, 1, [-1 2; 7 9;]); v = [exp(-p(:,1).^2 - 2.0 * p(:,2).^2)]; tsgLoadValues(lGridA, v); [mVan] = tsgEvaluateHierarchy(lGridB, p); Coeff = mVan \ v; tsgLoadHCoefficients(lGridB, Coeff); pnts = [-1.0 + 3.0 * rand(13, 1), 7.0 + 2.0 * rand(13, 1)]; [tres] = tsgEvaluate(lGridA, pnts); [res] = tsgEvaluate(lGridB, pnts); if (norm(tres - res) > 1.E-11) error(['Mismatch in tsgEvaluateHierarchy: localp grid solve']); end [lGridA, p] = tsgMakeSequence('_tsgcoretests_mlA', 2, 1, 'rleja', 'level', 5, [1 2; 1 2;]); [lGridB, p] = tsgMakeSequence('_tsgcoretests_mlB', 2, 1, 'rleja', 'level', 5, [1 2; 1 2;]); v = [exp(-p(:,1).^2 - 2.0 * p(:,2).^2)]; tsgLoadValues(lGridA, v); [mVan] = tsgEvaluateHierarchy(lGridB, p); Coeff = mVan \ v; tsgLoadHCoefficients(lGridB, Coeff); pnts = [1.0 + rand(32, 2)]; [tres] = tsgEvaluate(lGridA, pnts); [res] = tsgEvaluate(lGridB, pnts); if (norm(tres - res) > 1.E-11) error(['Mismatch in tsgEvaluateHierarchy: sequence solve']); end tsgDeleteGrid(lGridA); tsgDeleteGrid(lGridB); % this tests the hierarchical support [lGrid, p] = tsgMakeWavelet('_tsgcoretests_ml', 1, 1, 2, 1); [res] = tsgGetHSupport(lGrid); tres = [1.0, 1.0, 1.0, 1.5, 1.5, 0.75, 0.75, 0.75, 0.75]'; if (norm(tres - res) > 1.E-11) error(['Mismatch in tsgGetHSupport: wavelet support']); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgIntegrate() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeGlobal('_tsgcoretests_int', 1, 1, 'gauss-hermite', 'level', 2, [], [0.0,]); v = [p.^2]; tsgLoadValues(lGrid, v) [I] = tsgIntegrate(lGrid); if (abs(I - pi^0.5 / 2.0) > 1.E-11) error('Mismatch in tsgIntegrate(): case 1'); end [lGrid, p] = tsgMakeGlobal('_tsgcoretests_int', 1, 1, 'gauss-hermite', 'level', 2, [], [2.0,]); v = [sqrt(2.0) * ones(size(v,1), 1)]; tsgLoadValues(lGrid, v) [I] = tsgIntegrate(lGrid); if (abs(I - sqrt(2.0) * pi^0.5 / 2.0) > 1.E-11) error('Mismatch in tsgIntegrate(): case 2'); end tsgDeleteGrid(lGrid); disp(['Core I/O and evaluate PASS']); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgGetInterpolationWeights() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGridA, p] = tsgMakeGlobal('_tsgcoretests_IntA', 2, 1, 'fejer2', 'level', 4); [lGridB, p] = tsgMakeGlobal('_tsgcoretests_IntB', 2, 1, 'fejer2', 'level', 4); v = [exp(-p(:,1).^2 - 2.0 * p(:,2).^2)]; tsgLoadValues(lGridA, v); pnts = [-1.0 + 2.0 * rand(32, 2)]; [tres] = tsgEvaluate(lGridA, pnts); [A] = tsgGetInterpolationWeights(lGridB, pnts); res = A * v; if (norm(tres - res) > 1.E-11) error(['Mismatch in tsgGetInterpolationWeights: global case']); end [lGridA, p] = tsgMakeSequence('_tsgcoretests_IntA', 2, 1, 'min-delta', 'level', 7); [lGridB, p] = tsgMakeSequence('_tsgcoretests_IntB', 2, 1, 'min-delta', 'level', 7); v = [exp(-p(:,1).^2 - 2.0 * p(:,2).^2)]; tsgLoadValues(lGridA, v); pnts = [-1.0 + 2.0 * rand(32, 2)]; [tres] = tsgEvaluate(lGridA, pnts); [A] = tsgGetInterpolationWeights(lGridB, pnts); res = A * v; if (norm(tres - res) > 1.E-11) error(['Mismatch in tsgGetInterpolationWeights: global case']); end tsgDeleteGrid(lGridA); tsgDeleteGrid(lGridB); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgEstimateAnisotropicCoefficients() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeGlobal('_tsgcoretests_ans', 2, 1, 'rleja', 'level', 9); v = [exp(p(:,1) + p(:,2).^2)]; tsgLoadValues(lGrid, v); [c] = tsgEstimateAnisotropicCoefficients(lGrid, 'iptotal'); if (abs(c(1) / c(2) - 2.0) > 0.2) error('Mismatch in tsgEstimateAnisotropicCoefficients(): total degree'); end [c] = tsgEstimateAnisotropicCoefficients(lGrid, 'ipcurved'); if (length(c) ~= 4) error('Mismatch in tsgEstimateAnisotropicCoefficients(): curved dimensions'); end if ((abs(c(1) / c(2) - 2.0) > 0.2) || (c(3) > 0.0) || (c(4) > 0.0)) error('Mismatch in tsgEstimateAnisotropicCoefficients(): curved'); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgRefineAnisotropic() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeSequence('_tsgcoretests_refA', 3, 1, 'leja', 'level', 3, [], [], [], [], [3, 2, 1]); if ((sum((abs(p(:,1) - sqrt(1.0/3.0)) < 0.0001)) == 0) || (sum((abs(p(:,2) - sqrt(1.0/3.0)) < 0.0001)) > 0) || (sum((abs(p(:,3) - sqrt(1.0/3.0)) < 0.0001)) > 0)) error('Mismatch in tsgRefineAnisotropic(): limits in make'); end v = [exp(-p(:,1).^2 - p(:,2).^2)]; tsgLoadValues(lGrid, v); tsgRefineAnisotropic(lGrid, 'iptotal', 5, 0); [p] = tsgGetNeededPoints(lGrid); if (size(p, 1) == 0) error('Mismatch in tsgRefineAnisotropic(): did not refine'); end if ((sum((abs(p(:,2) - sqrt(1.0/3.0)) < 0.0001)) > 0) || (sum((abs(p(:,3) - sqrt(1.0/3.0)) < 0.0001)) > 0)) error('Mismatch in tsgRefineAnisotropic(): limits refine using existing limits'); end tsgRefineAnisotropic(lGrid, 'iptotal', 10, 0, [3, 2, 2]); [p] = tsgGetNeededPoints(lGrid); if (size(p, 1) == 0) error('Mismatch in tsgRefineAnisotropic(): did not refine'); end if ((sum((abs(p(:,2) - sqrt(1.0/3.0)) < 0.0001)) > 0) || (sum((abs(p(:,3) - 1.0) < 0.0001)) == 0) || (sum((abs(p(:,3) - sqrt(1.0/3.0)) < 0.0001)) > 0)) error('Mismatch in tsgRefineAnisotropic(): limits refine using new limits'); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgRefineSurplus() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_refS', 3, 1, 'localp', 3, 1, [], [], [], [1, 2, 3]); if ((sum((abs(p(:,1) - 0.5) < 0.0001)) > 0) || (sum((abs(p(:,2) - 0.25) < 0.0001)) > 0)) error('Mismatch in tsgRefineSurplus(): limits in make'); end v = [exp(-p(:,1).^2 - p(:,2).^2)]; tsgLoadValues(lGrid, v); tsgRefineSurplus(lGrid, 1.E-8, 'classic', 0); [p] = tsgGetNeededPoints(lGrid); if (size(p, 1) == 0) error('Mismatch in tsgRefineSurplus(): did not refine local polynomial'); end if ((sum((abs(p(:,1) - 0.5) < 0.0001)) > 0) || (sum((abs(p(:,2) - 0.25) < 0.0001)) > 0)) error('Mismatch in tsgRefineSurplus(): limits refine using existing limits'); end tsgRefineSurplus(lGrid, 1.E-8, 'classic', 0, [2, 2, 3]); [p] = tsgGetNeededPoints(lGrid); if (size(p, 1) == 0) error('Mismatch in tsgRefineSurplus(): did not refine on second pass'); end if ((sum((abs(p(:,1) - 0.5) < 0.0001)) == 0) || (sum((abs(p(:,1) - 0.25) < 0.0001)) > 0) || (sum((abs(p(:,2) - 0.25) < 0.0001)) > 0)) error('Mismatch in tsgRefineSurplus(): limits refine using new limits'); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgCancelRefine() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_cref', 3, 1, 'localp', 4, 2); v = [exp(-p(:,1).^2 -0.5 * p(:,2).^2 -2.0 * p(:,3).^2)]; tsgLoadValues(lGrid, v); [p] = tsgGetNeededPoints(lGrid); if (max(size(p)) > 0) error('Mismatch in cancel refine: did not load values'); end tsgRefineSurplus(lGrid, 1.E-4, 'direction'); [p] = tsgGetNeededPoints(lGrid); if (max(size(p)) == 0) error('Mismatch in cancel refine: did not set refinement at output -1'); end tsgCancelRefine(lGrid); [p] = tsgGetNeededPoints(lGrid); if (max(size(p)) > 0) error('Mismatch in cancel refine: did not cancel the refinement'); end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgMergeRefine() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGridA, p] = tsgMakeGlobal('_tsgcoretests_refA', 2, 1, 'fejer2', 'level', 4); [lGridB, p] = tsgMakeGlobal('_tsgcoretests_refB', 2, 1, 'fejer2', 'level', 4); v = [exp(-p(:,1).^2 -p(:,2).^2)]; tsgLoadValues(lGridA, v); tsgLoadValues(lGridB, v); tsgRefineAnisotropic(lGridA, 'iptotal', 10, 0); tsgRefineAnisotropic(lGridB, 'iptotal', 10, 0); [p] = tsgGetNeededPoints(lGridA); v = [exp(-p(:,1).^2 -p(:,2).^2)]; tsgLoadValues(lGridA, v); tsgMergeRefine(lGridB) [p1] = tsgGetPoints(lGridA); [p2] = tsgGetPoints(lGridB); if (norm(p1 - p2) > 1.E-11) error('Mismatch in tsgMergeRefine(): case 2, tsgGetPoints()') end p = [-1.0 + 2.0 * rand(20, 2)]; [vB] = tsgEvaluate(lGridB, p); if (norm(vB) > 1.E-11) error('Mismatch in tsgMergeRefine(): case 3, tsgEvaluate() not zero'); end [p] = tsgGetPoints(lGridB); v = [exp(-p(:,1).^2 -p(:,2).^2)]; tsgLoadValues(lGridB, v); p = [-1.0 + 2.0 * rand(30, 2)]; [vA] = tsgEvaluate(lGridA, p); [vB] = tsgEvaluate(lGridB, p); if (norm(vA - vB) > 1.E-11) error('Mismatch in tsgMergeRefine(): case 3, tsgEvaluate() not equal'); end tsgDeleteGrid(lGridA); tsgDeleteGrid(lGridB); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgGetHCoefficients() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % covered in tsgEvaluateHierarchy() %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgLoadHCoefficients() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % covered in tsgEvaluateHierarchy() disp(['Refinement functions PASS']); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgReloadGrid()/tsgLoadGridFromFile() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeGlobal('_tsgcoretests_ch', 3, 7, 'chebyshev', 'iptotal', 5); [lGrid2] = tsgReloadGrid('_tsgcoretests_ch'); if (lGrid2.sName ~= '_tsgcoretests_ch') error('Mismatch in tsgReloadGrid() could not reload grid: sName'); end if (lGrid2.sType ~= 'Global') error('Mismatch in tsgReloadGrid() could not reload grid: sType'); end if ((lGrid2.iDim ~= 3) || (lGrid2.iOut ~= 7)) error('Mismatch in tsgReloadGrid() could not reload grid: iDim and iOut'); end [lGrid3] = tsgLoadGridFromFile('_tsgcoretests_ch2', lGrid2.sFilename); if ((lGrid3.iDim ~= 3) || (lGrid3.iOut ~= 7)) error('Mismatch in tsgLoadGridFromFile() could not load grid: iDim and iOut'); end tsgDeleteGrid(lGrid); disp(['Utility functions PASS']); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgDifferentiate() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeGlobal('_tsgcoretests_diff', 2, 3, 'leja', 'iptotal', 3); num_p = length(p); f = @(x) [x(1), x(1)*x(2)*x(2), x(2)*x(2)]; Df = @(x) [1, 0; x(2)*x(2), 2*x(1)*x(2); 0, 2*x(2)]; vals = zeros(num_p, 3); for i=1:num_p vals(i,:) = f(p(i,:)); end tsgLoadValues(lGrid, vals); % Single point. p0 = 2 * rand(1, 2) - 1.0; tsgDf0 = tsgDifferentiate(lGrid, p0); if (norm(tsgDf0 - Df(p0)) > 1E-10) error(['Mismatch in tsgDifferentiate: single point case']); end % Multiple points pk = 2 * rand(5, 2) - 1.0; tsgDfk = tsgDifferentiate(lGrid, pk); for i=1:5 if (norm(tsgDfk{i} - Df(pk(i,:))) > 1E-10) error(['Mismatch in tsgDifferentiate: multi point case']); end end tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgGetDifferentiationWeights() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeGlobal('_tsgcoretests_diffw', 2, 3, 'leja', 'iptotal', 3); num_p = length(p); f = @(x) [x(1), x(1)*x(2)*x(2), x(2)*x(2)]; Df = @(x) [1, 0; x(2)*x(2), 2*x(1)*x(2); 0, 2*x(2)]; vals = zeros(num_p, 3); for i=1:num_p vals(i,:) = f(p(i,:)); end tsgLoadValues(lGrid, vals); % Single point. p0 = 2 * rand(1, 2) - 1.0; tsgW0 = tsgGetDifferentiationWeights(lGrid, p0); if (norm(vals' * tsgW0 - Df(p0)) > 1E-10) error(['Mismatch in tsgGetDifferentiationWeights: single point case']); end % Multiple points pk = 2 * rand(5, 2) - 1.0; tsgWk = tsgGetDifferentiationWeights(lGrid, pk); for i=1:5 if (norm(vals' * tsgWk{i} - Df(pk(i,:))) > 1E-10) error(['Mismatch in tsgGetDifferentiationWeights: multi point case']); end end tsgDeleteGrid(lGrid); disp(['Differentiation PASS']); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgLoadConstructedPoints() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% lrules = {'leja', 'clenshaw-curtis', 'localp'}; ldepts = {10, 5, 5}; lmodes = {'global', 'global', 'localp'}; for i = 1:2 if lmodes{i} == 'global' [lGrid, p] = tsgMakeGlobal('_tsgcoretests_ref', 2, 1, lrules{i}, 'iptotal', ldepts{i}); [lGrid2, ~] = tsgMakeGlobal('_tsgcoretests_ll', 2, 1, lrules{i}, 'iptotal', ldepts{i} - 3); elseif lmodes{i} == 'localp' [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_ref', 2, 1, lrules{i}, ldepts{i}); [lGrid2, ~] = tsgMakeLocalPolynomial('_tsgcoretests_ll', 2, 1, lrules{i}, ldepts{i} - 3); end v = exp(p(:,1) + p(:,2)); tsgLoadValues(lGrid, v); tsgLoadConstructedPoints(lGrid2, p, v); if (~tsgUsingConstruction(lGrid2)) error(['Dynamic refinement not enabled after a call to tsgLoadConstructedPoints() i = ', num2str(i)]) end rnd = rand(20, 2); [ref_result] = tsgEvaluate(lGrid, rnd); [ll_result] = tsgEvaluate(lGrid2, rnd); if (norm(ref_result - ll_result) > 1.E-14) error(['Dynamically loaded grid evals did not match the original grid result. i = ', num2str(i)]) end pp = tsgGetPoints(lGrid2); if (norm(ref_result - ll_result) > 1.E-14) error(['Dynamically loaded grid points did not match the original grid result. i = ', num2str(i)]) end tsgCancelRefine(lGrid2); if (tsgUsingConstruction(lGrid2)) error(['Dynamic refinement failed to finalize. i = ', num2str(i)]) end end tsgDeleteGrid(lGrid); tsgDeleteGrid(lGrid2); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% tsgGetCandidateConstructionAnisotropic() %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [lGrid, p] = tsgMakeGlobal('_tsgcoretests_tt', 2, 1, 'clenshaw-curtis', 'iptotal', 2); pp = tsgGetCandidateConstructionAnisotropic(lGrid, 'iptotal', 0); if (norm(sortrows(p) - sortrows(pp)) > 1.E-14) error(['Dynamically loaded grid points did not return the grid points.']) end [lGrid, p] = tsgMakeLocalPolynomial('_tsgcoretests_tt', 2, 1, 'localp', 3, 1); pp = tsgGetCandidateConstructionSurplus(lGrid, 1.E-3, 'classic', 0); if (norm(sortrows(p) - sortrows(pp)) > 1.E-14) error(['Dynamically loaded grid points did not return the grid points.']) end tsgDeleteGrid(lGrid); disp(['Dynamic construction PASS']); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% disp(['']); disp(['All Tasmanian Tests Completed Successfully']); end TASMANIAN-8.1/InterfaceMATLAB/tsgDeleteGrid.m000066400000000000000000000007631470551176200204000ustar00rootroot00000000000000function tsgDeleteGrid(lGrid) % % tsgDeleteGrid(lGrid) % % deletes all of the background files used by the grid % % INPUT: % % lGrid: a grid list created by tsgMakeGrid(...) % % NOTE: lGrid gets deleted and it can no longer be used % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sFileG = regexprep(sFileG, '\\ ', ' '); if (exist(sFileG, 'file') == 2) delete(sFileG); end lFiles.all = 1; tsgCleanTempFiles(lGrid, lFiles); end TASMANIAN-8.1/InterfaceMATLAB/tsgDeleteGridByName.m000066400000000000000000000010321470551176200214620ustar00rootroot00000000000000function tsgDeleteGridByName(sGridName) % % tsgDeleteGridByName(sGridName) % % deletes all of the background files used by the grid with name sGridName, % this function is to be used if the grid class lGrid has been lost % % NOTE: lGrid containing the sGridName can no longer be used % % INPUT: % % sGridName: the name of the grid to be deleted, i.e. the sGridName % parameter given to makeGrid(...) % lGrid.sName = sGridName; tsgDeleteGrid(lGrid); lGrid.sFilename = tsgMakeGridFilename(sGridName); tsgDeleteGrid(lGrid); end TASMANIAN-8.1/InterfaceMATLAB/tsgDifferentiate.m000066400000000000000000000041571470551176200211420ustar00rootroot00000000000000function [result] = tsgDifferentiate(lGrid, mX) % % [result] = tsgDifferentiate(lGrid, points) % % differentiates the interpolant at the points of interest and returns the result % this should be called after the grid has been created and after values % have been loaded % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % mX: an array of size [num_x, dimensions] % specifies the points where the interpolant should be differentiated % Note: do not confuse points here with the nodes of the grid % here points are user specified points to differentiate the % interpolant (or approximation) % % OUTPUT: % % result: if num_x is 1, this is the [outputs, dimensions] sized % Jacobian array/matrix of the surrogate model at mX; % if num_x is >1, this is a cell array of size [num_x] whose i-th % entry is the [outputs, dimensions] sized Jacobian array/matrix % of the surrogate model at mX(i,:). % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -differentiate']; sCommand = [sCommand, ' -gridfile ', sFileG]; tsgWriteMatrix(sFileX, mX); sCommand = [sCommand, ' -xf ', sFileX]; lClean.sFileX = 1; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1, ['Warning: Command had non-empty output:\n']); disp(cmdout); end raw_result = tsgReadMatrix(sFileO); num_x = size(mX, 1); num_dims = size(mX, 2); num_outs = size(raw_result, 2) / num_dims; % NOTE: C++ TASMANIAN arrays are stored row-major, but MATLAB assumes 1D vectors are column-major. if (num_x == 1) result = reshape(raw_result, [num_dims, num_outs])'; else result = cell(num_x, 1); for i=1:num_x result{i} = reshape(raw_result(i,:), [num_dims, num_outs])'; end end end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgEstimateAnisotropicCoefficients.m000066400000000000000000000030761470551176200247000ustar00rootroot00000000000000function [coefficients] = tsgEstimateAnisotropicCoefficients(lGrid, sType, iOut) % % [coefficients] = tsgEstimateAnisotropicCoefficients(lGrid, sType, iOut) % % computes anisotropic weights corresponding to sType and output iOut % % NOTE: this can be called only for global and sequence grids % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % sType: (string giving the tensor selection strategy) % 'level' 'curved' 'tensor' 'iptensor' % 'iptotal' 'ipcurved' 'qptotal' 'qpcurved' % % iOut: (integer giving the output to be used for the refinement) % selects which output to use for refinement % % OUTPUT: % % coefficients: (vector) % contains the anisotropic coefficients % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getanisotropy']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -type ', sType]; if (exist('iOut')) sCommand = [sCommand, ' -refout ', num2str(iOut)]; end % read the points for the grid sCommand = [sCommand, ' -of ',sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end [coefficients] = tsgReadMatrix(sFileO); end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgEvaluate.m000066400000000000000000000036161470551176200201360ustar00rootroot00000000000000function [result] = tsgEvaluate(lGrid, mX) % % [result] = tsgEvaluate(lGrid, points) % % evaluates the intepolant at the points of interest and returns the result % this should be called after the grid has been created and after values % have been loaded % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % mX: an array of size [num_x, dimensions] % specifies the points where the interpolant should be evaluated % Note: do not confuse points here with the nodes of the grid % here points are user specified points to evaluate the % interpolant (or approximation) % % NOTE: if lGrid has a field gpuDevice and if Tasmanian is build with % CUBLAS or CUDA options, then this will attempt to use the GPU % for acceleration. The gpuDevice should be an integer corresponding % to a valid Nvidia CUDA device, run tsgCoreTests() to see the % device list visible to Tasmanian and the corresponding number % % OUTPUT: % % result: an array of size [num_x, iOut] % the values of the interpolant at the corresponding points % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -evaluate']; sCommand = [sCommand, ' -gridfile ', sFileG]; tsgWriteMatrix(sFileX, mX); sCommand = [sCommand, ' -xf ', sFileX]; lClean.sFileX = 1; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; if (isfield(lGrid, 'gpuDevice')) sCommand = [sCommand, ' -gpuid ', num2str(lGrid.gpuDevice)]; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1, ['Warning: Command had non-empty output:\n']); disp(cmdout); end [result] = tsgReadMatrix(sFileO); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgEvaluateHierarchy.m000066400000000000000000000053061470551176200217730ustar00rootroot00000000000000function [vals] = tsgEvaluateHierarchy(lGrid, mX) % % [vals] = tsgEvaluateHierarchy(lGrid, mX) % % it gives the weights for interpolation (or approximation) % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) command % % mX: an array of size [num_x, dimensions] % specifies the points where the basis funcitons should be evaluated % Note: do not confuse points here with the nodes of the grid % here points are user specified points to evaluate the % hierarchical basis functions % % OUTPUT: % % vals: if lGrid is Global or Sequence % vals is an array of size [num_x, number_of_points] % if lGrid is LocalPolynomial or Wavelet % vals is a sparse matrix of size [num_x, number_of_points] % % in both cases, vals returns % the values associated with the hierarchical basis funcitons % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); if (strcmp(lGrid.sType, 'global') || strcmp(lGrid.sType, 'sequence') || strcmp(lGrid.sType, 'fourier')) sCommand = [sTasGrid,' -evalhierarchyd']; else sCommand = [sTasGrid,' -evalhierarchys']; end sCommand = [sCommand, ' -gridfile ', sFileG]; tsgWriteMatrix(sFileX, mX); sCommand = [sCommand, ' -xf ', sFileX]; lClean.sFileX = 1; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end if (strcmp(lGrid.sType, 'global') || strcmp(lGrid.sType, 'sequence')) [vals] = tsgReadMatrix(sFileO); elseif (strcmp(lGrid.sType, 'fourier')) [tmp] = tsgReadMatrix(sFileO); vals = tmp(:,1:2:end) + i * tmp(:,2:2:end); % i is unit imaginary else sFileO = regexprep(sFileO, '\\ ', ' '); fid = fopen(sFileO); TSG = fread(fid, [1, 3], '*char'); if (TSG == 'TSG') D = fread(fid, [1, 3], '*int'); Rows = D(1); Cols = D(2); NNZ = D(3); pntr = fread(fid, [Rows+1], '*int')'; indx = fread(fid, [NNZ], '*int')'; vals = fread(fid, [NNZ], '*double')'; rindx = ones(NNZ, 1); for r = 1:Rows rindx((pntr(r)+1):(pntr(r+1))) = r; end %[Rows, Cols, NNZ] vals = sparse(rindx, double(indx + 1.0), vals, double(Rows), double(Cols), double(NNZ)); else frewind(fid); end fclose(fid); end end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgExample.m000066400000000000000000000560711470551176200177660ustar00rootroot00000000000000function tsgExample(bFast) % % tsgExample() % % this is example source code on how to call the different functions % this does the exact same thing as the C++ example % % bFast: if this exists, then only the first two tests are executed %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 1: % % integrate: f(x,y) = exp(-x^2) * cos(y) over [-1,1] x [-1,1] % using classical Smolyak grid with Clenshaw-Curtis points and weights % dim = 2; level = 6; order = 0; % not used by Clenshaw-Curtis rule [weights, points] = tsgMakeQuadrature(dim, 'clenshaw-curtis', 'level', level, order); I = weights' * (exp(-points(:,1).^2) .* cos(points(:,2))); % I is the approximated quadrature E = 2.513723354063905e+00; % E is the "exact" solution computed to 16 decimal places E = abs(I - E); %E = abs(I - quad(@(x)(exp(-x.^2)), -1, 1, 1.E-14)*quad(@(x)(cos(x)), -1, 1, 1.E-14)); disp(['----------------------------------------------------------------------------']); disp([' Example 1: integrate f(x,y) = exp(-x^2) * cos(y), using clenshaw-curtis level nodes']); disp([' at level ',num2str(level)]); disp([' grid has ',num2str(size(points,1)),' points']); disp([' integral: ',num2str(I,16)]); disp([' error: ',num2str(E,16)]); disp([' ']); level = 7; [weights, points] = tsgMakeQuadrature(dim, 'clenshaw-curtis', 'level', level, order); I = weights' * (exp(-points(:,1).^2) .* cos(points(:,2))); % I is the approximated quadrature E = 2.513723354063905e+00; % E is the "exact" solution computed to 16 decimal places E = abs(I - E); disp([' at level ',num2str(level)]); disp([' grid has ',num2str(size(points,1)),' points']); disp([' integral: ',num2str(I,16)]); disp([' error: ',num2str(E,16),' (rounded to 14 decimal places)']); disp([' ']); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 2: % % integrate: f(x,y) = exp(-x^2) * cos(y) over (x,y) in [-5,5] x [-2,3] % using Gauss-Patterson rules chosen to integrate exactly polynomials of % total degree up to degree specified by prec % dim = 2; prec = 20; domain = [-5, 5; -2, 3]; order = 0; % not used by Gauss-Patterson rule [weights, points] = tsgMakeQuadrature(dim, 'gauss-patterson', 'qptotal', prec, order, domain); I = weights' * (exp(-points(:,1).^2) .* cos(points(:,2))); % I is the approximated quadrature E = 1.861816427518323e+00; % E is the "exact" solution computed to 16 decimal places E = abs(I - E); %E = abs(I - quad(@(x)(exp(-x.^2)), -1, 1, 1.E-14)*quad(@(x)(cos(x)), -1, 1, 1.E-14)); disp(['----------------------------------------------------------------------------']); disp([' Example 2: integrate f(x,y) = exp(-x^2) * cos(y) over [-5,5] x [-2,3] using Gauss-Patterson nodes']); disp([' at precision ',num2str(prec)]); disp([' grid has ',num2str(size(points,1)),' points']); disp([' integral: ',num2str(I,16)]); disp([' error: ',num2str(E,16)]); disp([' ']); prec = 40; [weights, points] = tsgMakeQuadrature(dim, 'gauss-patterson', 'qptotal', prec, order, domain); I = weights' * (exp(-points(:,1).^2) .* cos(points(:,2))); % I is the approximated quadrature E = 1.861816427518323e+00; % E is the "exact" solution computed to 16 decimal places E = abs(I - E); disp([' at precision ',num2str(prec)]); disp([' grid has ',num2str(size(points,1)),' points']); disp([' integral: ',num2str(I,16)]); disp([' error: ',num2str(E,16)]); disp([' ']); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if (exist('bFast')) % this is used for automated testing, ignore return; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 3: % % integrate: f(x,y) = exp(-x^2) * cos(y) over (x,y) in [-5,5] x [-2,3] % using Gauss-Patterson, Clenshaw-Curtis and Gauss-Legendre rules and % compare the results % dim = 2; domain = [-5, 5; -2, 3]; order = 0; E = 1.861816427518323e+00; % E is the "exact" solution computed to 16 decimal places disp(['----------------------------------------------------------------------------']); disp([' Example 3: integrate f(x,y) = exp(-x^2) * cos(y) over [-5,5] x [-2,3] using different rules']); disp([' ']); disp([' Clenshaw-Curtis Gauss-Legendre Gauss-Patterson']); disp([' precision nodes error nodes error nodes error']); for prec = 9:4:30 tt = num2str(prec); ss = [blanks(6 - length(tt)),tt]; [weights, points] = tsgMakeQuadrature(dim, 'clenshaw-curtis', 'qptotal', prec, order, domain); I = weights' * (exp(-points(:,1).^2) .* cos(points(:,2))); tt = num2str(size(points,1)); ss = [ss,' ',blanks(5 - length(tt)),tt]; tt = num2str(abs(I-E),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; ss = [ss,blanks(30 - length(ss))]; [weights, points] = tsgMakeQuadrature(dim, 'gauss-legendre', 'qptotal', prec, order, domain); I = weights' * (exp(-points(:,1).^2) .* cos(points(:,2))); tt = num2str(size(points,1)); ss = [ss,' ',blanks(5 - length(tt)),tt]; tt = num2str(abs(I-E),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; ss = [ss,blanks(60 - length(ss))]; [weights, points] = tsgMakeQuadrature(dim, 'gauss-patterson', 'qptotal', prec, order, domain); I = weights' * (exp(-points(:,1).^2) .* cos(points(:,2))); tt = num2str(size(points,1)); ss = [ss,blanks(5 - length(tt)),tt]; tt = num2str(abs(I-E),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; disp(ss); end disp([' ']); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 4: % % interpolate: f(x,y) = exp(-x^2) * cos(y) % over [2,3] x [2,3] % with a rule that exactly interpolates polynomials of total degree up to % degree specified by prec % % NOTE: any grid with name '_tsgExample4' will be overwritten by the % tsgMakeGlobal() command % dim = 2; outs = 1; prec = 6; [lGrid, points] = tsgMakeGlobal('_tsgExample4', dim, outs, 'clenshaw-curtis', 'iptotal', prec, [2 3; 2 3]); vals = (exp(-points(:,1).^2) .* cos(points(:,2))); tsgLoadValues(lGrid, vals); [res] = tsgEvaluate(lGrid, [2.3, 2.7]); disp(['----------------------------------------------------------------------------']); disp([' Example 4: interpolate f(x,y) = exp(-x^2) * cos(y) over [2,3] x [2,3]']); disp([' using clenshaw-curtis iptotal rule']); disp([' using polynomials of total degree up to ',num2str(prec)]); disp([' grid has ',num2str(size(points,1)),' points']); disp([' interpolant at (2.3,2.7): ',num2str(res,16)]); disp([' error: ',num2str(abs(res - exp(-2.3^2) * cos(2.7)),16)]); disp([' ']); prec = 12; [lGrid, points] = tsgMakeGlobal('_tsgExample4', dim, outs, 'clenshaw-curtis', 'iptotal', prec, [2 3; 2 3]); vals = (exp(-points(:,1).^2) .* cos(points(:,2))); tsgLoadValues(lGrid, vals); [res] = tsgEvaluate(lGrid, [2.3, 2.7]); disp([' using polynomials of total degree up to ',num2str(prec)]); disp([' grid has ',num2str(size(points,1)),' points']); disp([' interpolant at (2.3,2.7): ',num2str(res,16)]); disp([' error: ',num2str(abs(res - exp(-2.3^2) * cos(2.7)),16)]); disp([' ']); tsgDeleteGrid(lGrid); % clear all temporary used files %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 5: % % interpolate: f(x1,x2,x3,x4) = exp(-x1^2) * cos(x2) * exp(-x3^2) * cos(x4) % with Global and Sequence Leja rules % dim = 4; outs = 1; prec = 15; tic; [lGrid, points] = tsgMakeGlobal('_tsgExample5', dim, outs, 'leja', 'iptotal', prec); gstage1 = toc; disp(['----------------------------------------------------------------------------']); disp([' Example 5: interpolate f(x1,x2,x3,x4) = exp(-x1^2) * cos(x2) * exp(-x3^2) * cos(x4)']); disp([' comparign the performance of Global and Sequence grids with leja nodes']); disp([' using polynomials of total degree up to ',num2str(prec)]); disp([' grid has ',num2str(size(points,1)),' points']); disp([' both grids are evaluated at 1000 random points']); disp([' ']); vals = (exp(-points(:,1).^2) .* cos(points(:,2))) .* (exp(-points(:,3).^2) .* cos(points(:,4))); tic; tsgLoadValues(lGrid, vals); gstage2 = toc; pnts = [-1 + 2 * rand(1000, 4)]; tres = (exp(-pnts(:,1).^2) .* cos(pnts(:,2))) .* (exp(-pnts(:,3).^2) .* cos(pnts(:,4))); tic; [res] = tsgEvaluate(lGrid, pnts); gstage3 = toc; gerr = max(abs(res - tres)); tic; [lGrid, points] = tsgMakeSequence('_tsgExample5', dim, outs, 'leja', 'iptotal', prec); sstage1 = toc; vals = (exp(-points(:,1).^2) .* cos(points(:,2))) .* (exp(-points(:,3).^2) .* cos(points(:,4))); tic; tsgLoadValues(lGrid, vals); sstage2 = toc; tic; [sres] = tsgEvaluate(lGrid, pnts); sstage3 = toc; serr = max(abs(sres - tres)); disp([' Stage Global Grid Sequence Grid']); disp([' make grid ',num2str(gstage1),' ',num2str(sstage1),' seconds']); disp([' load values ',num2str(gstage2),' ',num2str(sstage2),' seconds']); disp([' evaluate ',num2str(gstage3),' ',num2str(sstage3),' seconds']); disp([' error ',num2str(gerr),' ',num2str(serr)]); disp([' The difference between the two approximations is: ',num2str(max(abs(res - sres)))]); disp([' NOTE: the MATLAB interface has the additional overhead of reading/writing files to the work folder']); disp([' the results here are not the best comparison between sequence and global rules']); disp([' ']); tsgDeleteGrid(lGrid); % clear all temporary used files % % I tried to make an example here with more outputs, but the cost of % tsgLoadValues() is dominated by the reading/writing of the files and is % hence not a good comparison. See the C++ example. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 6: % % interpolate: f(x,y) = exp(-x^2) * cos(y) % using different refinement schemes % dim = 2; outs = 1; prec = 3; [lGrid1, points] = tsgMakeGlobal('_tsgExample6a', dim, outs, 'leja', 'iptotal', prec); [lGrid2, points] = tsgMakeGlobal('_tsgExample6b', dim, outs, 'leja', 'iptotal', prec); [lGrid3, points] = tsgMakeGlobal('_tsgExample6c', dim, outs, 'leja', 'iptotal', prec); vals = (exp(-points(:,1).^2) .* cos(points(:,2))); tsgLoadValues(lGrid1, vals); tsgLoadValues(lGrid2, vals); tsgLoadValues(lGrid3, vals); pnts = [-1 + 2 * rand(1000, 2)]; tres = exp(-pnts(:,1).^2) .* cos(pnts(:,2)); disp(['----------------------------------------------------------------------------']); disp([' Example 6: interpolate: f(x,y) = exp(-x^2) * cos(y) ']); disp([' using leja nodes and different refinement schemes']); disp([' the error is estimated as the maximum from 1000 random points']); disp([' ']); % clear all temporary used files disp([' Total Degree Curved Surplus']); disp([' iteration nodes error nodes error nodes error']); nump1 = size(points, 1); nump2 = size(points, 1); nump3 = size(points, 1); for iI = 1:10 tt = num2str(iI); ss = [blanks(6 - length(tt)),tt]; [points] = tsgRefineAnisotropic(lGrid1, 'iptotal', 10); vals = (exp(-points(:,1).^2) .* cos(points(:,2))); tsgLoadValues(lGrid1, vals); nump1 = nump1 + size(points, 1); tt = num2str(nump1); ss = [ss,' ',blanks(5 - length(tt)),tt]; [res] = tsgEvaluate(lGrid1, pnts); tt = num2str(max(abs(res - tres)),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; ss = [ss,blanks(30 - length(ss))]; [points] = tsgRefineAnisotropic(lGrid2, 'ipcurved', 10); vals = (exp(-points(:,1).^2) .* cos(points(:,2))); tsgLoadValues(lGrid2, vals); nump2 = nump2 + size(points, 1); tt = num2str(nump2); ss = [ss,' ',blanks(5 - length(tt)),tt]; [res] = tsgEvaluate(lGrid2, pnts); tt = num2str(max(abs(res - tres)),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; ss = [ss,blanks(60 - length(ss))]; [points] = tsgRefineSurplus(lGrid3, 1.E-10, 'classic'); vals = (exp(-points(:,1).^2) .* cos(points(:,2))); tsgLoadValues(lGrid3, vals); nump3 = nump3 + size(points, 1); tt = num2str(nump3); ss = [ss,blanks(5 - length(tt)),tt]; [res] = tsgEvaluate(lGrid3, pnts); tt = num2str(max(abs(res - tres)),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; disp(ss); end disp([' ']); tsgDeleteGrid(lGrid1); tsgDeleteGrid(lGrid2); tsgDeleteGrid(lGrid3); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 7: % % interpolate: f(x,y) = exp(-x^2) * cos(y) % using different local polynomial rules % dim = 2; outs = 1; prec = 7; disp(['----------------------------------------------------------------------------']); disp([' Example 7: interpolate: f(x,y) = exp(-x^2) * cos(y) ']); disp([' using localp and semi-localp rules with depth ',num2str(prec)]); disp([' the error is estimated as the maximum from 1000 random points']); disp([' ']); % clear all temporary used files [lGrid, points] = tsgMakeLocalPolynomial('_tsgExample7', dim, outs, 'localp', prec, 2); vals = (exp(-points(:,1).^2) .* cos(points(:,2))); tsgLoadValues(lGrid, vals); pnts = [-1 + 2 * rand(1000, 2)]; tres = exp(-pnts(:,1).^2) .* cos(pnts(:,2)); [res] = tsgEvaluate(lGrid, pnts); disp([' Number of points: ',num2str(size(points, 1))]); disp([' Error for localp: ',num2str(max(abs(res - tres)))]); [lGrid, points] = tsgMakeLocalPolynomial('_tsgExample7', dim, outs, 'semi-localp', prec, 2); vals = (exp(-points(:,1).^2) .* cos(points(:,2))); tsgLoadValues(lGrid, vals); [res] = tsgEvaluate(lGrid, pnts); disp([' Error for semi-localp: ',num2str(max(abs(res - tres)))]); disp([' Note: semi-localp wins this competition because the function is very smooth']); disp([' ']); tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 8: % % interpolate f(x,y) = cos(0.5 * pi * x) * cos(0.5 * pi * y) % using different local polynomial rules % dim = 2; outs = 1; prec = 7; disp(['----------------------------------------------------------------------------']); disp([' Example 8: interpolate f(x,y) = cos(0.5 * pi * x) * cos(0.5 * pi * y) ']); disp([' using localp and localp-zero rules with depth ',num2str(prec)]); disp([' the error is estimated as the maximum from 1000 random points']); disp([' ']); [lGrid, points] = tsgMakeLocalPolynomial('_tsgExample8', dim, outs, 'localp', prec, 2); vals = (cos(0.5 * pi * points(:,1)) .* cos(0.5 * pi * points(:,2))); tsgLoadValues(lGrid, vals); pnts = [-1 + 2 * rand(1000, 2)]; tres = (cos(0.5 * pi * pnts(:,1)) .* cos(0.5 * pi * pnts(:,2))); [res] = tsgEvaluate(lGrid, pnts); disp([' localp Number of points: ',num2str(size(points, 1)),' Error: ',num2str(max(abs(res - tres)))]); [lGrid, points] = tsgMakeLocalPolynomial('_tsgExample8', dim, outs, 'localp-zero', prec-1, 2); vals = (cos(0.5 * pi * points(:,1)) .* cos(0.5 * pi * points(:,2))); tsgLoadValues(lGrid, vals); [res] = tsgEvaluate(lGrid, pnts); disp([' localp-zero Number of points: ',num2str(size(points, 1)),' Error: ',num2str(max(abs(res - tres)))]); disp([' Note: localp-zero wins this competition because the function is zero at the boundary']); disp([' ']); tsgDeleteGrid(lGrid); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 9: % % interpolate f(x,y) = exp(- x) / (1 + 100 * exp(- 10 * y)) % using different local refinement schemes % dim = 2; outs = 1; prec = 2; tol = 1.E-5; disp(['----------------------------------------------------------------------------']); disp([' Example 9: interpolate f(x,y) = exp(- x) / (1 + 100 * exp(- 10 * y)) ']); disp([' the error is estimated as the maximum from 1000 random points']); disp([' tolerance is set at 1.E-5 and maximal order polynomials are used']); disp([' ']); [lGrid1, points] = tsgMakeLocalPolynomial('_tsgExample9a', dim, outs, 'localp', prec, -1); vals = exp(-points(:,1)) ./ (1 + 100 * exp(-10 * points(:,2))); tsgLoadValues(lGrid1, vals); pnts = [-1 + 2 * rand(1000, 2)]; tres = exp(-pnts(:,1)) ./ (1 + 100 * exp(-10 * pnts(:,2))); [lGrid2, points] = tsgMakeLocalPolynomial('_tsgExample9b', dim, outs, 'localp', prec, -1); tsgLoadValues(lGrid2, vals); disp([' Classic FDS']); disp([' iteration nodes error nodes error']); nump1 = size(points, 1); nump2 = size(points, 1); for iI = 1:7 tt = num2str(iI); ss = [blanks(6 - length(tt)),tt]; [points] = tsgRefineSurplus(lGrid1, tol, 'classic'); vals = exp(-points(:,1)) ./ (1 + 100 * exp(-10 * points(:,2))); tsgLoadValues(lGrid1, vals); nump1 = nump1 + size(points, 1); tt = num2str(nump1); ss = [ss,' ',blanks(5 - length(tt)),tt]; [res] = tsgEvaluate(lGrid1, pnts); tt = num2str(max(abs(res - tres)),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; ss = [ss,blanks(30 - length(ss))]; [points] = tsgRefineSurplus(lGrid2, tol, 'fds'); vals = exp(-points(:,1)) ./ (1 + 100 * exp(-10 * points(:,2))); tsgLoadValues(lGrid2, vals); nump2 = nump2 + size(points, 1); tt = num2str(nump2); ss = [ss,' ',blanks(5 - length(tt)),tt]; [res] = tsgEvaluate(lGrid2, pnts); tt = num2str(max(abs(res - tres)),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; disp(ss); end disp([' ']); tsgDeleteGrid(lGrid1); tsgDeleteGrid(lGrid2); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 10: % % interpolate f(x,y) = exp(- x) / (1 + 100 * exp(- 10 * y)) % using local polynomails and wavelets % dim = 2; outs = 1; prec = 1; tol = 1.E-5; disp(['----------------------------------------------------------------------------']); disp([' Example 10: interpolate f(x,y) = exp(- x) / (1 + 100 * exp(- 10 * y)) ']); disp([' using local polynomials and wavelets']); disp([' the error is estimated as the maximum from 1000 random points']); disp([' ']); [lGrid1, points] = tsgMakeLocalPolynomial('_tsgExample10a', dim, outs, 'localp', prec+2, 1); vals = exp(-points(:,1)) ./ (1 + 100 * exp(-10 * points(:,2))); tsgLoadValues(lGrid1, vals); pnts = [-1 + 2 * rand(1000, 2)]; tres = exp(-pnts(:,1)) ./ (1 + 100 * exp(-10 * pnts(:,2))); [lGrid2, points] = tsgMakeWavelet('_tsgExample10b', dim, outs, prec, 1); vals = exp(-points(:,1)) ./ (1 + 100 * exp(-10 * points(:,2))); tsgLoadValues(lGrid2, vals); disp([' Polynomials Wavelets']); disp([' iteration nodes error nodes error']); nump1 = size(points, 1); nump2 = size(points, 1); for iI = 1:8 tt = num2str(iI); ss = [blanks(6 - length(tt)),tt]; [points] = tsgRefineSurplus(lGrid1, tol, 'fds'); vals = exp(-points(:,1)) ./ (1 + 100 * exp(-10 * points(:,2))); tsgLoadValues(lGrid1, vals); nump1 = nump1 + size(points, 1); tt = num2str(nump1); ss = [ss,' ',blanks(5 - length(tt)),tt]; [res] = tsgEvaluate(lGrid1, pnts); tt = num2str(max(abs(res - tres)),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; ss = [ss,blanks(30 - length(ss))]; [points] = tsgRefineSurplus(lGrid2, tol, 'fds'); vals = exp(-points(:,1)) ./ (1 + 100 * exp(-10 * points(:,2))); tsgLoadValues(lGrid2, vals); nump2 = nump2 + size(points, 1); tt = num2str(nump2); ss = [ss,' ',blanks(5 - length(tt)),tt]; [res] = tsgEvaluate(lGrid2, pnts); tt = num2str(max(abs(res - tres)),5); ss = [ss,' ',blanks(12 - length(tt)),tt]; disp(ss); end disp([' Note: wavelets have a larger Lebesgue constant and thus wavelets are not always better than polynomials.']); disp([' ']); tsgDeleteGrid(lGrid1); tsgDeleteGrid(lGrid2); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % EXAMPLE 11: % % interpolate: f(x,y,z) = 1/((1+4x^2)*(1+5y^2)*(1+6z^2)) % using classical and conformal transformation % dim = 3; prec = 12; outs = 1; [lGrid, points] = tsgMakeGlobal('_tsgExample11a', dim, outs, 'clenshaw-curtis', 'iptotal', prec, [], [], [], []); vals = 1.0 ./ ((1.0 + 4.0*points(:,1).^2).*(1.0 + 5.0*points(:,2).^2).*(1.0 + 6.0*points(:,3).^2)); tsgLoadValues(lGrid, vals); pnts = [-1 + 2 * rand(1000, 3)]; tres = 1.0 ./ ((1.0 + 4.0*pnts(:,1).^2).*(1.0 + 5.0*pnts(:,2).^2).*(1.0 + 6.0*pnts(:,3).^2)); [res] = tsgEvaluate(lGrid, pnts); err1 = max(abs(tres - res)); nump1 = size(points, 1); [lGrid, points] = tsgMakeGlobal('_tsgExample11a', dim, outs, 'clenshaw-curtis', 'iptotal', prec, [], [], [], [], 'asin', [4, 4, 4]); vals = 1.0 ./ ((1.0 + 4.0*points(:,1).^2).*(1.0 + 5.0*points(:,2).^2).*(1.0 + 6.0*points(:,3).^2)); tsgLoadValues(lGrid, vals); [res] = tsgEvaluate(lGrid, pnts); err2 = max(abs(tres - res)); [lGrid, points] = tsgMakeLocalPolynomial('_tsgExample11a', dim, outs, 'localp', prec-4, 2); vals = 1.0 ./ ((1.0 + 4.0*points(:,1).^2).*(1.0 + 5.0*points(:,2).^2).*(1.0 + 6.0*points(:,3).^2)); tsgLoadValues(lGrid, vals); err3 = max(abs(tres - res)); [lGrid, points] = tsgMakeLocalPolynomial('_tsgExample11a', dim, outs, 'localp', prec-4, 2, [], 'asin', [4, 4, 4]); vals = 1.0 ./ ((1.0 + 4.0*points(:,1).^2).*(1.0 + 5.0*points(:,2).^2).*(1.0 + 6.0*points(:,3).^2)); tsgLoadValues(lGrid, vals); [res] = tsgEvaluate(lGrid, pnts); err4 = max(abs(tres - res)); nump2 = size(points, 1); disp(['----------------------------------------------------------------------------']); disp([' Example 11: interpolate f(x,y,z) = 1/((1+4x^2)*(1+5y^2)*(1+6z^2))']); disp([' using conformal transformation']); disp([' the error is estimated as the maximum from 1000 random points']); disp(['']); disp([' Grid Type nodes error regular error conformal']); disp([' Global ', num2str(nump1,'%5d'),' ', num2str(err1, '%1.3e'), ' ', num2str(err2, '%1.3e')]); disp([' Localp ', num2str(nump2,'%5d'),' ', num2str(err3, '%1.3e'), ' ', num2str(err4, '%1.3e')]); disp([' Note: conformal maps address specific problems with the region of analyticity of a function']); disp([' the map can accelerate or slow down convergence depending on the problem']); disp([' ']); tsgDeleteGrid(lGrid); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetCandidateConstructionAnisotropic.m000066400000000000000000000075741470551176200255410ustar00rootroot00000000000000function [new_points] = tsgGetCandidateConstructionAnisotropic(lGrid, sType, iOutOrAnisotropy, vLimitLevels) % % [new_points] = tsgGetCandidateConstructionAnisotropic(lGrid, % sType, iOutputOrAnisotropy, vLimitLevels) % % returns points for asynchronous (dynamic) construction where % the "more important" points are sorted first, the sorting is done % using anisotropic criteria % see getCandidateConstructionPoints() in the on-line manual % % NOTE: this will call the C++ method beginConstruction() which will % clear any currently set refinement % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % sType: (string giving the tensor selection strategy) % 'level' 'curved' 'tensor' 'iptensor' % 'iptotal' 'ipcurved' 'qptotal' 'qpcurved' % % iOutOrAnisotropy: (integer or vector of integers) % if it is a single integer, it will be used to indicate % the output to use to compute the ansiotropic weights % (could be -1 for Sequence and Fourier grids) % could be a vector of integers indicating anisotropic weights % which will skip computing the weights % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D using % clenshaw-curtis rule, [1, 99] forces the grid to have % at most 3 possible values in the first variable and % ~2^99 (practicallyt infinite) number in the second % direction. vLimitLevels overwrites iMinNew, if using % vLimitLevels the number of new points may be less than % iMinNew, increase iMinNew until a desired number of % points is selected % % OUTPUT: % % new_points: array % the new set of sorted needed points % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getconstructpnts']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -type ', sType]; if (max(size(iOutOrAnisotropy)) == 1) sCommand = [sCommand, ' -refout ', num2str(iOutOrAnisotropy)]; else if (min(size(iOutOrAnisotropy)) ~= 1) error(' iOutOrAnisotropy must be a vector, i.e., one row or one column'); end if (max(size(iOutOrAnisotropy)) ~= lGrid.iDim) error(' iOutOrAnisotropy must be a vector of size iDim'); end if (size(iOutOrAnisotropy, 1) > size(iOutOrAnisotropy, 2)) tsgWriteMatrix(sFileW, iOutOrAnisotropy'); else tsgWriteMatrix(sFileW, iOutOrAnisotropy); end lClean.sFileW = 1; sCommand = [sCommand, ' -anisotropyfile ', sFileW]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= lGrid.iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end % read the points for the grid if (nargout == 1) sCommand = [sCommand, ' -of ',sFileO]; lClean.sFileO = 1; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end if (nargout == 1) [new_points] = tsgReadMatrix(sFileO); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgGetCandidateConstructionSurplus.m000066400000000000000000000103041470551176200247050ustar00rootroot00000000000000function [new_points] = tsgGetCandidateConstructionSurplus(lGrid, fTolerance, sRefinementType, iOut, vLimitLevels, mCorrection) % % [new_points] = tsgGetCandidateConstructionSurplus( % lGrid, fTolerance, sRefinementType, iOut, vLimitLevels) % % returns points for asynchronous (dynamic) construction where % the "more important" points are sorted first, the sorting is done % using anisotropic criteria % see getCandidateConstructionPoints() in the on-line manual % % This function works for Local Polynomial and Wavelet grids only % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % fTolerance: (real non-negative number) % refine only in neighborhood of points that satisfy % max(point_surplus / max_value) > fTolerance % where max(...) is taken over all outputs % point_surplus is the hierarchical surplus % max_value is the largest loaded value associated with each output % % % sRefinementType: (string indicating the refinement type) % 'classic' 'parents' 'direction' 'fds' 'stable' % only for Local Polynomial and Wavelet grids % % iOut: (integer giving the output to be used for the refinement) % selects which output to use for refinement, must be specified for % Global Grids, other grid can omit this or set it to [] to indicate % the use of all outputs % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D using % localp rule, [1, 99] forces the grid to have % at most 3 possible values in the first variable and % ~2^99 (practicallyt infinite) number in the second % direction. % % mCorrection: (optional matrix with size num_points by num_outputs or 1) % the surpluses in the refinement procedure will be multiplied % by the correction % if iOut is -1, then one weight must be given per output and % the columns must match the number of outputs % if iOut is specified, mCorrection must have one column % % OUTPUT: % % new_points: (optional) array % the new set of sorted needed points % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getconstructpnts']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -tolerance ', num2str(fTolerance,17)]; if ((exist('sRefinementType')) && (max(size(sRefinementType)) ~= 0)) sCommand = [sCommand, ' -reftype ', sRefinementType]; end if (exist('iOut') && (max(size(iOut)) ~= 0)) sCommand = [sCommand, ' -refout ', num2str(iOut)]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= lGrid.iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end % set correction if (exist('mCorrection') && (max(size(mCorrection)) ~= 0)) if (min(size(mCorrection)) ~= 1) error(' mCorrection must be a vector, i.e., one row or one column'); end tsgWriteMatrix(sFileV, mCorrection); lClean.sFileV = 1; sCommand = [sCommand, ' -valsfile ', sFileV]; end % read the points for the grid if (nargout == 1) sCommand = [sCommand, ' -of ',sFileO]; lClean.sFileO = 1; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end if (nargout == 1) [new_points] = tsgReadMatrix(sFileO); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgGetDifferentiationWeights.m000066400000000000000000000043001470551176200234640ustar00rootroot00000000000000function [weights] = tsgGetDifferentiationWeights(lGrid, mX) % % [weights] = tsgGetDifferentiationWeights(lGrid, mX) % % it gives the weights for differentiation weights % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) command % % mX: an array of size [num_x, dimensions] % specifies the points where the derivative should be evaluated % Note: do not confuse points here with the nodes of the grid % here points are user specified points to evaluate the % derivative % % OUTPUT: % % weights: if num_x == 1, this is the [num_points, dimensions] sized array/matrix % of derivative weights for the point mX; % if num_x > 2, this is a cell array of size [num_x] whose i-th % entry is a [num_points, dimensions] sized array/vector of derivative % weights for mX(i,:); % % The Jacobian of f(mX(i,:)) is approximated by: % % f(points)' * weights, if num_x == 1 % f(points)' * weights{i}, if num_x >= 2 % % where points is obtained from the tsgGetPoints() function. % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getdiffweights']; sCommand = [sCommand, ' -gridfile ', sFileG]; tsgWriteMatrix(sFileX, mX); sCommand = [sCommand, ' -xf ', sFileX]; lClean.sFileX = 1; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end raw_result = tsgReadMatrix(sFileO); num_x = size(mX, 1); num_dims = size(mX, 2); num_points = size(raw_result, 2) / num_dims; % NOTE: C++ TASMANIAN arrays are stored row-major, but MATLAB assumes 1D vectors are column-major. if (num_x == 1) weights = reshape(raw_result, [num_dims, num_points])'; else weights = cell(num_x, 1); for i=1:num_x weights{i} = reshape(raw_result(i,:), [num_dims, num_points])'; end end end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetHCoefficients.m000066400000000000000000000022551470551176200215370ustar00rootroot00000000000000function [coefficients] = tsgGetHCoefficients(lGrid) % % [coefficients] = tsgGetHCoefficients(lGrid) % % retrieves the get the hierarchical coefficients of the grid % % INPUT: % % lGrid: a grid list created by tsgMake***(...) command % % OUTPUT: % % coefficients: the hierarchical coefficients of the grid in an array of dimension [num_points, iOut] % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getcoefficients']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end [coefficients] = tsgReadMatrix(sFileO); end if (strcmp(lGrid.sType, 'fourier')) % convert to complex matrix if needed coefficients = coefficients(:, 1:2:end) + i * coefficients(:, 2:2:end); % i is unit imaginary end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetHSupport.m000066400000000000000000000017421470551176200206120ustar00rootroot00000000000000function [coefficients] = tsgGetHSupport(lGrid) % % [coefficients] = tsgGetHSupport(lGrid) % % retrieves the supprot of the hierarchical basis functions % % INPUT: % % lGrid: a grid list created by tsgMake***(...) command % % OUTPUT: % % coefficients: the support of the basis functions in an array of size [num_points, num_dimensions] % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -gethsupport']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end [coefficients] = tsgReadMatrix(sFileO); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetInterpolationWeights.m000066400000000000000000000030121470551176200232000ustar00rootroot00000000000000function [weights] = tsgGetInterpolationWeights(lGrid, mX) % % [weights] = tsgGetInterpolationWeights(lGrid, mX) % % it gives the weights for interpolation (or approximation) % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) command % % mX: an array of size [num_x, dimensions] % specifies the points where the interpolant should be evaluated % Note: do not confuse points here with the nodes of the grid % here points are user specified points to evaluate the % interpolant (or approximation) % % OUTPUT: % % weights: an array of size [num_x, number_of_points] % the values associated with the interpolant at those points % % f(mX(i,:)) is approximated by weights(i,:)' * f(points) % where points is obtained from the tsgGetPoints() function % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getinterweights']; sCommand = [sCommand, ' -gridfile ', sFileG]; tsgWriteMatrix(sFileX, mX); sCommand = [sCommand, ' -xf ', sFileX]; lClean.sFileX = 1; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end [weights] = tsgReadMatrix(sFileO); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetNeededIndexes.m000066400000000000000000000017741470551176200215370ustar00rootroot00000000000000function [pindex] = tsgGetNeededIndexes(lGrid) % % [pindex] = tsgGetPointIndexes(lGrid) % % retrieves the indexes of the points associated with an existing grid % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) command % % OUTPUT: % % pindex: the indexes associated with the currently loaded points % in an array of dimension [num_poits, iDim] % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getneededindexes']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end [pindex] = tsgReadMatrix(sFileO); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetNeededPoints.m000066400000000000000000000021621470551176200214040ustar00rootroot00000000000000function [points] = tsgGetNeededPoints(lGrid) % % [points] = tsgGetNeededPoints(lGrid) % % retrieves the points associated with an existing grid that require % funciton values % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) command % % OUTPUT: % % points: the needed points of the grid in an array of dimension [num_poits, iDim] % the needed points are those generated by tsgMakeXXX(...) or % tsgRefineXXX(...) commands, before the call to tagLoadValues(...) % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getneeded']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end [points] = tsgReadMatrix(sFileO); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetPaths.build.m000066400000000000000000000006071470551176200212020ustar00rootroot00000000000000function [sFiles, sTasGrid] = tsgGetPaths() % % [sFiles, sTasGrid] = tsgGetPaths() % % You should edit the following variables accordingly % sTasGrdid should be the path + executable of that tasgrid wrapper % sFile should be root of the work files directory % % it is recommended to use absolute path sTasGrid = ['@Tasmanian_matlab_tasgrid@']; sFiles = ['@Tasmanian_matlab_workdir@']; end TASMANIAN-8.1/InterfaceMATLAB/tsgGetPaths.install.m000066400000000000000000000006071470551176200215510ustar00rootroot00000000000000function [sFiles, sTasGrid] = tsgGetPaths() % % [sFiles, sTasGrid] = tsgGetPaths() % % You should edit the following variables accordingly % sTasGrdid should be the path + executable of that tasgrid wrapper % sFile should be root of the work files directory % % it is recommended to use absolute path sTasGrid = ['@Tasmanian_matlab_tasgrid@']; sFiles = ['@Tasmanian_matlab_workdir@']; end TASMANIAN-8.1/InterfaceMATLAB/tsgGetPoints.m000066400000000000000000000016561470551176200203060ustar00rootroot00000000000000function [points] = tsgGetPoints(lGrid) % % [points] = tsgGetPoints(lGrid) % % retrieves the points associated with an existing grid % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) command % % OUTPUT: % % points: the points of the grid in an array of dimension [num_poits, iDim] % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getpoints']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end [points] = tsgReadMatrix(sFileO); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetPointsIndexes.m000066400000000000000000000017741470551176200216270ustar00rootroot00000000000000function [pindex] = tsgGetPointsIndexes(lGrid) % % [pindex] = tsgGetPointIndexes(lGrid) % % retrieves the indexes of the points associated with an existing grid % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) command % % OUTPUT: % % pindex: the indexes associated with the currently loaded points % in an array of dimension [num_poits, iDim] % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getpointsindexes']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end [pindex] = tsgReadMatrix(sFileO); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetPolynomialSpaces.m000066400000000000000000000025631470551176200223120ustar00rootroot00000000000000function [poly] = tsgGetPolynomialSpaces(lGrid, bInterpolate) % % [poly] = tsgGetPolynomialSpaces(lGrid, bInterpolate) % % returns a matrix corresponding to the polynomial space that is integrated % or interpolated exactly % % NOTE: this can be called only for global and sequence grids % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % bInterpolate: (boolean) % specifies whether to consider integration or interpolation % % OUTPUT: % % poly: (matrix of size num_polynomial_basis_functions X iDim) % The polynomial space is % span{ x.^poly(i,:) }, for x in R^d and i = 1 ... size(poly, 1) % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getpoly']; sCommand = [sCommand, ' -gridfile ', sFileG]; if (bInterpolate) sCommand = [sCommand, ' -type iptotal']; else sCommand = [sCommand, ' -type qptotal']; end sCommand = [sCommand, ' -of ',sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end [poly] = tsgReadMatrix(sFileO); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgGetQuadrature.m000066400000000000000000000020451470551176200211400ustar00rootroot00000000000000function [weights, points] = tsgGetQuadrature(lGrid) % % [weights, points] = tsgGetQuadrature(lGrid) % % retrieves the quadrature points and weights from an existing grid % % INPUT: % % lGrid: a grid list created by a tsgMakeXXX(...) command % % OUTPUT: % % weights: the quadrature weights % % points: the quadrature nodes, i.e., quad(f) = weights' * f(points) % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -getquadrature']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end [wp] = tsgReadMatrix(sFileO); weights = wp(:,1); points = wp(:,2:end); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgIntegrate.m000066400000000000000000000016521470551176200203100ustar00rootroot00000000000000function [result] = tsgIntegrate(lGrid) % % [result] = tsgEvaluate(lGrid, points) % % returns the integral of the interpolant % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % OUTPUT: % % result: a vector of size [iOut] % the values of the integrals of each output % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -integrate']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end [result] = tsgReadMatrix(sFileO); end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgListGridsByName.m000066400000000000000000000010671470551176200213660ustar00rootroot00000000000000function tsgListGridsByName() % % tsgListGridsByName() % % prints a list of all grids in the WorkFiles folder regardless if they are % associated with lGrid class % [sFiles, sTasGrid] = tsgGetPaths(); lFileList = dir(sFiles); lGridIndexes = []; for iI = 1:length(lFileList) if (~isempty(findstr('_FileG', lFileList(iI).name))) lGridIndexes = [lGridIndexes, iI]; end end disp([' Grids in the work folder:']); disp([' ']); for iI = 1:length(lGridIndexes) line = lFileList(lGridIndexes(iI)).name; disp(line(1:end-6)); end disp([' ']); endTASMANIAN-8.1/InterfaceMATLAB/tsgLoadConstructedPoints.m000066400000000000000000000027511470551176200226610ustar00rootroot00000000000000function tsgLoadConstructedPoints(lGrid, mX, mY) % % tsgLoadConstructedPoints(lGrid, mX, mY) % % loads the combination of inputs (mX) and outputs (mY) into the grid % the points don't need to be in any particular order, but % the i-th row of mX has to correspond to the i-th row of mY % the points must be aligned to the gird, but may come from % any level, e.g., grid level 3 can accept points from level 4 or up % see loadConstructedPoints() in the on-line manual % % NOTE: this will call the C++ method beginConstruction() which will % clear any currently set refinement % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % mX : matrix of size N by number of dimensions % % mY : matrix of size N by number of outputs % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -loadconstructed']; sCommand = [sCommand, ' -gridfile ', sFileG]; tsgWriteMatrix(sFileX, mX); sCommand = [sCommand, ' -xf ', sFileX]; lClean.sFileX = 1; tsgWriteMatrix(sFileV, mY); sCommand = [sCommand, ' -vf ', sFileV]; lClean.sFileV = 1; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgLoadGridFromFile.m000066400000000000000000000035161470551176200215000ustar00rootroot00000000000000function [lGrid] = tsgLoadGridFromFile(sGridName, sFilename) % % [lGrid] = tsgLoadGridFromFile(sGridName, sFilename) % % Creates an lGrid object referencing an arbitrary file. % The temporary folder will still be used for data such as points, % weights and model values, therefore a unique name is still needed. % % The method is intended to simplify interfaces with other languages, % e.g., the grid can be constructed with C++ and stored in a file % then post-processing can done with MATLAB. % % Note: this does not check if there are already other lGrid objects % associated with the file, aliasing can cause issues here. % % INPUT: % % sGridName: unique identifier string used for temporary filenames % % sFilename: existing file holding a Tasmanian sparse grid % % OUTPUT: % % lGrid: list containing information about the sparse grid, % can be used to call other functions % if (exist(sFilename, 'file') ~= 2) error(['invalid filename, cannot find file: ',sFilename]); end [sFiles, sTasGrid] = tsgGetPaths(); lGrid.sName = sGridName; lGrid.sFilename = sFilename; sCommand = [sTasGrid,' -summary -gridfile ', sFilename]; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); end sLines = strsplit(cmdout, {'\n','\r'}); l1 = strsplit(sLines{2}); l2 = strsplit(sLines{3}); l3 = strsplit(sLines{4}); % create lGrid object lGrid.sName = sGridName; if (strcmp(l1{4}, 'Global')) lGrid.sType = 'global'; elseif (strcmp(l1{4}, 'Sequence')) lGrid.sType = 'sequence'; elseif (strcmp(l1{4}, 'Local')) lGrid.sType = 'localpolynomial'; elseif (strcmp(l1{4}, 'Wavelets')) lGrid.sType = 'wavelet'; elseif (strcmp(l1{4}, 'Fourier')) lGrid.sType = 'fourier'; end lGrid.iDim = str2num(l2{3}); lGrid.iOut = str2num(l3{3}); end TASMANIAN-8.1/InterfaceMATLAB/tsgLoadHCoefficients.m000066400000000000000000000026621470551176200217010ustar00rootroot00000000000000function tsgLoadHCoefficients(lGrid, mValues) % % tsgLoadHCoefficients(lGrid, mValues) % % loads the values of the target function at the needed points % % INPUT: % % lGrid: a grid list created by tsgMake***(...) command % % mValues: a matrix with dimension [num_needed_points, iOut] % each row corresponds to the values of the hierarchical % coefficients at the corresponding needed point. % The order and leading dimension must match the points % obtained form tsgGetNeededPoints(...) command % % OUTPUT: % % The grid file associated with lGrid is modified % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -setcoefficients']; sCommand = [sCommand, ' -gridfile ', sFileG]; if (strcmp(lGrid.sType, 'fourier')) mRealMat = zeros(size(mValues, 1), 2 * size(mValues, 2)); mRealMat(:, 1:2:end) = real(mValues); mRealMat(:, 2:2:end) = imag(mValues); mValues = mRealMat; end tsgWriteMatrix(sFileV, mValues); lClean.sFileV = 1; sCommand = [sCommand, ' -vf ', sFileV]; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgLoadValues.m000066400000000000000000000022571470551176200204270ustar00rootroot00000000000000function tsgLoadValues(lGrid, mValues) % % tsgLoadValues(lGrid, mValues) % % loads the values of the target function at the needed points % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) command % % mValues: a matrix with dimension [num_needed_points, iOut] % each row corresponds to the values of the outputs at the % corresponding needed point. The order and leading dimension must % match the points obtained form tsgGetNeededPoints(...) command % % OUTPUT: % % The grid file associated with lGrid is modified % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -loadvalues']; sCommand = [sCommand, ' -gridfile ', sFileG]; tsgWriteMatrix(sFileV, mValues); lClean.sFileV = 1; sCommand = [sCommand, ' -vf ', sFileV]; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end end tsgCleanTempFiles(lGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgMakeExoticQuadrature.m000066400000000000000000000041771470551176200224620ustar00rootroot00000000000000function lCustomRule = tsgMakeExoticQuadrature(iDepth, fShift, lWeightGrid, sDescription, bSymmetric) % % creates a custom-tabulated contain global exotic quadrature nodes and weights % % INPUT: % % iDepth: (integer non-negative) % controls the density of the grid % % fShift: (float) % the shift of the weight function % % lWeightGrid: (sparse grid of weight function) % list containing information about the surrogate/interpolant of the weight function; can be ASCII or binary format % % sDescription: (string) % description of the generated custom rule, e.g. "Exotic Quadrature 1" or "Sinc rule" % % bSymmetric: (bool) % if true, this declares that the weight function is symmetric % % OUTPUT: % % lCustomRule: (global grids of custom-tabulated rule) % % structure defining the fields % lCustomRule.sDescription % lCustomRule.iMaxLevel % lCustomRule.vLevels % lCustomRule.vPrecision % lCustomRule.vNodes % lCustomRule.vWeights % % see help tsgWriteCustomRuleFile.m for definition of each field of the structure if (isempty(sDescription)) error('sDescription cannot be empty'); end % generate filenames [~, sTasGrid] = tsgGetPaths(); lTempGrid.sName = ''; [~, ~, ~, ~, ~, sFileC, ~] = tsgMakeFilenames(lTempGrid); [sWeightFileG, ~, ~, ~, ~, ~, ~] = tsgMakeFilenames(lWeightGrid); sCommand = [sTasGrid,' -makeexoquad']; sCommand = [sCommand, ' -depth ', num2str(iDepth)]; sCommand = [sCommand, ' -shift ', num2str(fShift)]; sCommand = [sCommand, ' -weightfile ', sWeightFileG]; sCommand = [sCommand, ' -description ', '"', sDescription, '"']; if (bSymmetric) sCommand = [sCommand, ' -symmetric ']; end sCommand = [sCommand, ' -outputfile ', sFileC]; [~, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); end % create lCustomRule object lCustomRule = tsgReadCustomRuleFile(sFileC); lClean.sFileC = 1; tsgCleanTempFiles(lTempGrid, lClean); end TASMANIAN-8.1/InterfaceMATLAB/tsgMakeFilenames.m000066400000000000000000000021431470551176200210630ustar00rootroot00000000000000function [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid) % % [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid) % % given the paths from tsgGetPaths() it returns the filenames of all files associated with the name % [sFiles, sTasGrid] = tsgGetPaths(); if exist('getpid','builtin') id = getpid(); else id = feature('getpid'); end if (isfield(lGrid, 'sFilename')) % new convention, the filename is stored into the lGrid object sFileG = lGrid.sFilename; else % using the old naming convention sFileG = [sFiles, lGrid.sName,'_FileG']; % the filename to store the grid end sFileX = [sFiles, lGrid.sName,'.FileX',num2str(id)]; % file with points to evaluate the surrogate sFileV = [sFiles, lGrid.sName,'.FileV']; % file with values to be loaded sFileO = [sFiles, lGrid.sName,'.FileO',num2str(id)]; % file for output sFileW = [sFiles, lGrid.sName,'.FileW']; % file with anisotropic weights sFileC = [sFiles, lGrid.sName,'.FileC']; % file with the custom rule sFileL = [sFiles, lGrid.sName,'.FileL']; % file with level limits end TASMANIAN-8.1/InterfaceMATLAB/tsgMakeFourier.m000066400000000000000000000175571470551176200206120ustar00rootroot00000000000000function [lGrid, points] = tsgMakeFourier(sGridName, iDim, iOut, sType, iDepth, mTransformAB, vAnisotropy, sConformalMap, vConfromalWeights, vLimitLevels) % % [lGrid, points] = % tsgMakeFourier(sGridName, iDim, iOut, sType, iDepth, % mTransformAB, vAlphaBeta, vAnisotropy, % sConformalMap, vConfromalWeights) % % creates a new sparse grid using a Fourier rule % % INPUT: % % sGridName: the name of the grid, give it a string name, % i.e. 'myGrid' or '1' or 'pi314' % DO NOT LEAVE THIS EMPTY % % iDim: (integer, positive) % the number of inputs % % iOut: (integer, non-negative) % the number of outputs % % sType: (string giving the tensor selection strategy) % 'level' 'curved' 'hyperbolic' 'tensor' % 'iptotal' 'ipcurved' 'iphyperbolic' 'iptensor' % 'qptotal' 'qpcurved' 'qphyperbolic' 'qptensor' % % iDepth: (integer non-negative) % controls the density of the grid, i.e., the offset for the tensor % selection, the meaning of iDepth depends on sType % Example 1: sType == 'iptotal' will give a grid that interpolates % exactly all polynomials of degree up to and including iDepth % Example 2: sType == 'qptotal' will give a grid that integrates % exactly all polynomials of degree up to and including iDepth % % vAnisotropy: (optional vector of positive integers, length iDim or 2*iDim) % the anisotropic weights associated with sType % % mTransformAB: (optional matrix of size iDim x 2) % for all but gauss-laguerre and gauss-hermite grids, the % transform specifies the lower and upper bound of the domain % in each direction. For gauss-laguerre and gauss-hermite % grids, the transform gives the a and b parameters that % change the weight to % exp(-b (x - a)) and exp(-b (x - a)^2) % % lCustomRule: (global grids of custom-tabulated rule) % custom_rule can be either of 3 things: % % string containing filename with a defined custom name % % structure containing the filed lCustomRule.sFilename, % which is the name of a file containing the user defined % rule % % structure defining the fields % lCustomRule.sDescription % lCustomRule.iMaxLevel % lCustomRule.vLevels % lCustomRule.vPrecision % lCustomRule.vNodes % lCustomRule.vWeights % % see help tsgWriteCustomRuleFile.m for definition of % each field of the structure % % sConformalMap: (optional string giving the type of transform) % conformal maps provide a non-linear domain transform, % approximation (quadrature or interpolation) is done % on the composition of f and the transform. A suitable % transform could reduce the error by as much as an % order of magnitude. % % 'asin': truncated MacLaurin series of arch-sin % % vConfromalWeights: (optional parameters for the conformal trnasform) % 'asin': indicate the number of terms to keep after % truncation % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D using % clenshaw-curtis rule, [1, 99] forces the grid to have % at most 3 possible values in the first variable and % ~2^99 (practically infinite) number in the second % direction. vLimitLevels works in conjunction with % iDepth and sType, the points added to the grid will % obey both bounds % % OUTPUT: % % lGrid: list containing information about the sparse grid, can be used % to call other functions % % points: (optional) the points of the grid in an array % of dimension [num_points, dim] % % [lGrid, points] = % tsgMakeFourier(sGridName, iDim, iOut, sType, iDepth, % mTransformAB, vAnisotropy, % sConformalMap, vConfromalWeights) % if (~isnumeric(iDim) || ~isreal(iDim) || ~(rem(iDim,1) == 0) || ~(sum(size(iDim) == [1,1])) || ~(iDim > 0)) error('iDim must be a positive integer') end if (~isnumeric(iOut) || ~isreal(iOut) || ~(rem(iOut,1) == 0) || ~(sum(size(iOut) == [1,1])) || ~(iOut > 0)) error('iOut must be a positive integer') end % create lGrid object lGrid.sName = sGridName; lGrid.sFilename = tsgMakeGridFilename(sGridName); lGrid.iDim = iDim; lGrid.iOut = iOut; lGrid.sType = 'fourier'; % check for conflict with tsgMakeQuadrature if (strcmp(sGridName, '')) error('sGridName cannot be empty'); end % generate filenames [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -makefourier']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -dimensions ', num2str(lGrid.iDim)]; sCommand = [sCommand, ' -outputs ', num2str(lGrid.iOut)]; sCommand = [sCommand, ' -depth ', num2str(iDepth)]; sCommand = [sCommand, ' -type ', sType]; % set the domain transformation if (exist('mTransformAB') && (max(size(mTransformAB)) ~= 0)) if (size(mTransformAB, 2) ~= 2) error(' mTransformAB must be a matrix with 2 columns'); end if (size(mTransformAB, 1) ~= lGrid.iDim) error(' mTransformAB must be a matrix with iDim number of rows'); end tsgWriteMatrix(sFileV, mTransformAB); lClean.sFileV = 1; sCommand = [sCommand, ' -tf ',sFileV]; end % set anisotropy if (exist('vAnisotropy') && (max(size(vAnisotropy)) ~= 0)) if (min(size(vAnisotropy)) ~= 1) error(' vAnisotropy must be a vector, i.e., one row or one column'); end if (max(size(vAnisotropy)) ~= lGrid.iDim) error(' vAnisotropy must be a vector of size iDim'); end if (size(vAnisotropy, 1) > size(vAnisotropy, 2)) tsgWriteMatrix(sFileW, vAnisotropy'); else tsgWriteMatrix(sFileW, vAnisotropy); end lClean.sFileW = 1; sCommand = [sCommand, ' -anisotropyfile ', sFileW]; end % set conformal mapping if (exist('sConformalMap') && (max(size(sConformalMap)) ~= 0)) if (~exist('vConfromalWeights')) error(' sConformalMap requires vConfromalWeights') end sCommand = [sCommand, ' -conformaltype ', sConformalMap]; if (size(vConfromalWeights, 1) > size(vConfromalWeights, 2)) tsgWriteMatrix(sFileC, vConfromalWeights'); else tsgWriteMatrix(sFileC, vConfromalWeights); end lClean.sFileC = 1; sCommand = [sCommand, ' -conformalfile ', sFileC]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= lGrid.iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end % read the points for the grid if (nargout > 1) sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end if (nargout > 1) points = tsgReadMatrix(sFileO); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgMakeGlobal.m000066400000000000000000000272511470551176200203670ustar00rootroot00000000000000function [lGrid, points] = tsgMakeGlobal(sGridName, iDim, iOut, s1D, sType, iDepth, mTransformAB, vAlphaBeta, vAnisotropy, lCustomRule, sConformalMap, vConfromalWeights, vLimitLevels) % % [lGrid, points] = % tsgMakeGlobal(sGridName, iDim, iOut, s1D, sType, iDepth, % mTransformAB, vAlphaBeta, vAnisotropy, lCustomRule, % sConformalMap, vConfromalWeights) % % creates a new sparse grid using a global rule % % INPUT: % % sGridName: the name of the grid, give it a string name, % i.e. 'myGrid' or '1' or 'pi314' % DO NOT LEAVE THIS EMPTY % % iDim: (integer, positive) % the number of inputs % % iOut: (integer, non-negative) % the number of outputs % % s1D: (string for the underlying 1-D rule that induces the grid) % % Interpolation rules (Note: the quadrature induced by those rules is % constructed by integrating the interpolant) % % 'clenshaw-curtis' 'clenshaw-curtis-zero' 'fejer2' % 'leja' 'leja-odd' 'max-lebesgue' 'max-lebesgue-odd' % 'rleja' 'rleja-odd' 'rleja-double2' 'rleja-double4' % 'rleja-shifted' 'rleja-shifted-even' % 'min-lebesgue' 'min-lebesgue-odd' 'min-delta' 'min-delta-odd' % % 'chebyshev' 'chebyshev-odd' % approximation using roots of Chebyshev polynomials % non-nested case (in contrast to Clenshaw-Curtis nodes) % Note: the quadrature induced by those rules is % constructed by integrating the interpolant % % Quadrature rules, the weights target exactness with respect to the % highest polynomial degree possible % % 'gauss-legendre' 'gauss-legendre-odd' % approximation using roots of polynomials orthogonal in % measure Uniform % % 'gauss-patterson' (a.k.a. nested Gauss-Legendre) % Note: the nodes and weights are hard-coded hence there % is a limit on the highest possible depth % Note: nestedness gives an interpolation rule % % 'gauss-chebyshev1' 'gauss-chebyshev1-odd' % 'gauss-chebyshev2' 'gauss-chebyshev2-odd' % approximation using roots of polynomials orthogonal in % measures 1/sqrt(1-x^2) and sqrt(1-x^2) (respectively) % % 'gauss-gegenbauer' 'gauss-gegenbauer-odd' % approximation using roots of polynomials orthogonal in % measure (1-x^2)^alpha % % 'gauss-jacobi' % approximation using roots of polynomials orthogonal in % measure (1-x)^alpha * (1+x)^beta % % 'gauss-laguerre' % approximation using roots of polynomials orthogonal in % measure x^alpha * epx(-x) % % 'gauss-hermite' 'gauss-hermite-odd' % approximation using roots of polynomials orthogonal in % measure |x|^alpha * epx(-x^2) % % sType: (string giving the tensor selection strategy) % 'level' 'curved' 'hyperbolic' 'tensor' % 'iptotal' 'ipcurved' 'iphyperbolic' 'iptensor' % 'qptotal' 'qpcurved' 'qphyperbolic' 'qptensor' % % iDepth: (integer non-negative) % controls the density of the grid, i.e., the offset for the tensor % selection, the meaning of iDepth depends on sType % Example 1: sType == 'iptotal' will give a grid that interpolates % exactly all polynomials of degree up to and including iDepth % Example 2: sType == 'qptotal' will give a grid that integrates % exactly all polynomials of degree up to and including iDepth % % vAnisotropy: (optional vector of positive integers, length iDim or 2*iDim) % the anisotropic weights associated with sType % % vAlphaBeta: (optional vector of length 1 or 2) % vAlphaBeta(1) is the alpha parameter for Gegenbauer, Jacobi, % Hermite and Laguerre rules % vAlphaBeta(2) is the beta parameter for Jacobi rules % % mTransformAB: (optional matrix of size iDim x 2) % for all but gauss-laguerre and gauss-hermite grids, the % transform specifies the lower and upper bound of the domain % in each direction. For gauss-laguerre and gauss-hermite % grids, the transform gives the a and b parameters that % change the weight to % exp(-b (x - a)) and exp(-b (x - a)^2) % % lCustomRule: (global grids of custom-tabulated rule) % custom_rule can be either of 3 things: % % string containing filename with a defined custom name % % structure containing the filed lCustomRule.sFilename, % which is the name of a file containing the user defined % rule % % structure defining the fields % lCustomRule.sDescription % lCustomRule.iMaxLevel % lCustomRule.vLevels % lCustomRule.vPrecision % lCustomRule.vNodes % lCustomRule.vWeights % % see help tsgWriteCustomRuleFile.m for definition of % each field of the structure % % sConformalMap: (optional string giving the type of transform) % conformal maps provide a non-linear domain transform, % approximation (quadrature or interpolation) is done % on the composition of f and the transform. A suitable % transform could reduce the error by as much as an % order of magnitude. % % 'asin': truncated MacLaurin series of arch-sin % % vConfromalWeights: (optional parameters for the conformal trnasform) % 'asin': indicate the number of terms to keep after % truncation % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D using % clenshaw-curtis rule, [1, 99] forces the grid to have % at most 3 possible values in the first variable and % ~2^99 (practicallyt infinite) number in the second % direction. vLimitLevels works in conjunction with % iDepth and sType, the points added to the grid will % obey both bounds % % OUTPUT: % % lGrid: list containing information about the sparse grid, can be used % to call other functions % % points: (optional) the points of the grid in an array % of dimension [num_poits, dim] % % [lGrid, points] = % tsgMakeGlobal(sGridName, iDim, iOut, s1D, sType, iDepth, % mTransformAB, vAlphaBeta, vAnisotropy, lCustomRule, % sConformalMap, vConfromalWeights)% if (~isnumeric(iDim) || ~isreal(iDim) || ~(rem(iDim,1) == 0) || ~(sum(size(iDim) == [1,1])) || ~(iDim > 0)) error('iDim must be a positive integer') end if (~isnumeric(iOut) || ~isreal(iOut) || ~(rem(iOut,1) == 0) || ~(sum(size(iOut) == [1,1])) || ~(iOut > 0)) error('iOut must be a positive integer') end % create lGrid object lGrid.sName = sGridName; lGrid.sFilename = tsgMakeGridFilename(sGridName); lGrid.iDim = iDim; lGrid.iOut = iOut; lGrid.sType = 'global'; % check for conflict with tsgMakeQuadrature if (strcmp(sGridName, '')) error('sGridName cannot be empty'); end % generate filenames [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -makeglobal']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -dimensions ', num2str(lGrid.iDim)]; sCommand = [sCommand, ' -outputs ', num2str(lGrid.iOut)]; sCommand = [sCommand, ' -onedim ', s1D]; sCommand = [sCommand, ' -depth ', num2str(iDepth)]; sCommand = [sCommand, ' -type ', sType]; % set the domain transformation if (exist('mTransformAB') && (max(size(mTransformAB)) ~= 0)) if (size(mTransformAB, 2) ~= 2) error(' mTransformAB must be a matrix with 2 columns'); end if (size(mTransformAB, 1) ~= lGrid.iDim) error(' mTransformAB must be a matrix with iDim number of rows'); end tsgWriteMatrix(sFileV, mTransformAB); lClean.sFileV = 1; sCommand = [sCommand, ' -tf ',sFileV]; end % set anisotropy if (exist('vAnisotropy') && (max(size(vAnisotropy)) ~= 0)) if (min(size(vAnisotropy)) ~= 1) error(' vAnisotropy must be a vector, i.e., one row or one column'); end if (max(size(vAnisotropy)) ~= lGrid.iDim) error(' vAnisotropy must be a vector of size iDim'); end if (size(vAnisotropy, 1) > size(vAnisotropy, 2)) tsgWriteMatrix(sFileW, vAnisotropy'); else tsgWriteMatrix(sFileW, vAnisotropy); end lClean.sFileW = 1; sCommand = [sCommand, ' -anisotropyfile ', sFileW]; end % set alpha and beta if (exist('vAlphaBeta') && (max(size(vAlphaBeta)) ~= 0)) if (min(size(vAlphaBeta)) ~= 1) error(' vAlphaBeta must be a vector, i.e., one row or one column'); end if (max(size(vAlphaBeta)) > 2) error(' vAlphaBeta must be a vector of size at most 2'); end sCommand = [sCommand, ' -alpha ',num2str(vAlphaBeta(1), 16)]; if (max(size(vAlphaBeta)) > 1) sCommand = [sCommand, ' -beta ',num2str(vAlphaBeta(2), 16)]; end end % set custom rule if (strcmp(s1D, 'custom-tabulated')) if (exist('lCustomRule')) if (ischar(lCustomRule)) sCommand = [sCommand, ' -cf ', lCustomRule]; elseif (isfield(lCustomRule, 'filename')) % DEPRECATED syntax, do this for backward compatibility sCommand = [sCommand, ' -cf ', lCustomRule.filename]; elseif (isfield(lCustomRule, 'sFilename')) sCommand = [sCommand, ' -cf ', lCustomRule.sFilename]; else tsgWriteCustomRuleFile(sFileX, lCustomRule); lClean.sFileX = 1; sCommand = [sCommand, ' -cf ', sFileX]; end else disp(['ERROR: must provide a lCustomRule variable to use with a custom rule']); return; end end % set conformal mapping if (exist('sConformalMap') && (max(size(sConformalMap)) ~= 0)) if (~exist('vConfromalWeights')) error(' sConformalMap requires vConfromalWeights') end sCommand = [sCommand, ' -conformaltype ', sConformalMap]; if (size(vConfromalWeights, 1) > size(vConfromalWeights, 2)) tsgWriteMatrix(sFileC, vConfromalWeights'); else tsgWriteMatrix(sFileC, vConfromalWeights); end lClean.sFileC = 1; sCommand = [sCommand, ' -conformalfile ', sFileC]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= lGrid.iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end % read the points for the grid if (nargout > 1) sCommand = [sCommand, ' -of ', sFileO]; lClean.sFileO = 1; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end if (nargout > 1) points = tsgReadMatrix(sFileO); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgMakeGridFilename.m000066400000000000000000000005511470551176200215070ustar00rootroot00000000000000function sGridFilename = tsgMakeGridFilename(sGridName) % % sGridFilename = tsgMakeGridFilename(sGridName) % % given the paths from tsgGetPaths() it returns the filename for the grid % [sFiles, sTasGrid] = tsgGetPaths(); if exist('getpid','builtin') id = getpid(); else id = feature('getpid'); end sGridFilename = [sFiles, sGridName,'.tsgrid']; end TASMANIAN-8.1/InterfaceMATLAB/tsgMakeLocalPolynomial.m000066400000000000000000000136131470551176200222620ustar00rootroot00000000000000function [lGrid, points] = tsgMakeLocalPolynomial(sGridName, iDim, iOut, s1D, iDepth, iOrder, mTransformAB, sConformalMap, vConfromalWeights, vLimitLevels) % % [lGrid, points] % tsgMakeLocalPolynomial(sGridName, iDim, iOut, s1D, iDepth, iOrder, % mTransformAB, sConformalMap, vConfromalWeights, % vLimitLevels) % % creates a new sparse grid using a sequence rule % % INPUT: % % sGridName: the name of the grid, give it a string name, % i.e. 'myGrid' or '1' or 'pi314' % DO NOT LEAVE THIS EMPTY % % iDim: (integer, positive) % the number of inputs % % iOut: (integer, non-negative) % the number of outputs % % s1D: (string for the underlying 1-D rule that induces the grid) % % 'localp' 'localp-zero' 'semi-localp' 'localp-boundary' % % iDepth: (integer non-negative) % controls the density of the grid, % i.e., the number of levels to use % % % iOrder: (integer must be -1 or bigger) % -1 indicates largest possible order % 1 means linear, 2 means quadratic, etc. % % mTransformAB: (optional matrix of size iDim x 2) % for all but gauss-laguerre and gauss-hermite grids, the % transform specifies the lower and upper bound of the domain % in each direction. For gauss-laguerre and gauss-hermite % grids, the transform gives the a and b parameters that % change the weight to % exp(-b (x - a)) and exp(-b (x - a)^2) % % sConformalMap: (optional string giving the type of transform) % conformal maps provide a non-linear domain transform, % approximation (quadrature or interpolation) is done % on the composition of f and the transform. A suitable % transform could reduce the error by as much as an % order of magnitude. % % 'asin': truncated MacLaurin series of arch-sin % % vConfromalWeights: (optional parameters for the conformal trnasform) % 'asin': indicate the number of terms to keep after % truncation % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D [1, 99] forces % the grid to have at most 3 possible values in the first % variable and ~2^99 (practicallyt infinite) number in the % second direction. vLimitLevels works in conjunction with % iDepth, for each direction, we chose the lesser of the % vLimitLevels and iDepth % % OUTPUT: % % lGrid: list containing information about the sparse grid, can be used % to call other functions % % points: (optional) the points of the grid in an array % of dimension [num_poits, dim] % % [lGrid, points] = % tsgMakeLocalPolynomial(sGridName, iDim, iOut, s1D, iDepth, iOrder, % mTransformAB, sConformalMap, vConfromalWeights, % vLimitLevels) % % create lGrid object lGrid.sName = sGridName; lGrid.sFilename = tsgMakeGridFilename(sGridName); lGrid.iDim = iDim; lGrid.iOut = iOut; lGrid.sType = 'localpolynomial'; % check for conflict with tsgMakeQuadrature if (strcmp(sGridName, '')) error('sGridName cannot be empty'); end % generate filenames [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -makelocalpoly']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -dimensions ', num2str(lGrid.iDim)]; sCommand = [sCommand, ' -outputs ', num2str(lGrid.iOut)]; sCommand = [sCommand, ' -onedim ', s1D]; sCommand = [sCommand, ' -depth ', num2str(iDepth)]; sCommand = [sCommand, ' -order ', num2str(iOrder)]; % set the domain transformation if (exist('mTransformAB') && (max(size(mTransformAB)) ~= 0)) if (size(mTransformAB, 2) ~= 2) error(' mTransformAB must be a matrix with 2 columns'); end if (size(mTransformAB, 1) ~= lGrid.iDim) error(' mTransformAB must be a matrix with iDim number of rows'); end tsgWriteMatrix(sFileV, mTransformAB); lGlean.sFileV = 1; sCommand = [sCommand, ' -tf ',sFileV]; end % set conformal mapping if (exist('sConformalMap') && (max(size(sConformalMap)) ~= 0)) if (~exist('vConfromalWeights')) error(' sConformalMap requires vConfromalWeights') end sCommand = [sCommand, ' -conformaltype ', sConformalMap]; if (size(vConfromalWeights, 1) > size(vConfromalWeights, 2)) tsgWriteMatrix(sFileC, vConfromalWeights'); else tsgWriteMatrix(sFileC, vConfromalWeights); end lClean.sFileC = 1; sCommand = [sCommand, ' -conformalfile ',sFileC]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= lGrid.iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end % read the points for the grid if (nargout > 1) sCommand = [sCommand, ' -of ',sFileO]; lGlean.sFileO = 1; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end if (nargout > 1) points = tsgReadMatrix(sFileO); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgMakeQuadrature.m000066400000000000000000000273641470551176200213110ustar00rootroot00000000000000function [weights, points] = tsgMakeQuadrature(iDim, s1D, sType, iDepth, iOrder, mTransformAB, vAlphaBeta, vAnisotropy, lCustomRule, sConformalMap, vConfromalWeights, vLimitLevels) % % [weights, points] = tsgMakeQuadrature(iDim, s1D, sType, iDepth, iOrder, % mTransformAB, vAlphaBeta, vAnisotropy, lCustomRule, % sConformalMap, vConfromalWeights, vLimitLevels) % % creates a set of points and weights for integration % % INPUT: % % iDim: (integer, positive) % the number of inputs % % s1D: (string for the underlying 1-D rule that induces the grid) % % Interpolation rules (Note: the quadrature induced by those rules is % constructed by integrating the interpolant) % % 'clenshaw-curtis' 'clenshaw-curtis-zero' 'fejer2' % 'leja' 'leja-odd' 'max-lebesgue' 'max-lebesgue-odd' % 'rleja' 'rleja-odd' 'rleja-double2' 'rleja-double4' % 'rleja-shifted' 'rleja-shifted-even' % 'min-lebesgue' 'min-lebesgue-odd' 'min-delta' 'min-delta-odd' % % 'chebyshev' 'chebyshev-odd' % approximation using roots of Chebyshev polynomials % non-nested case (in contrast to Clenshaw-Curtis nodes) % Note: the quadrature induced by those rules is % constructed by integrating the interpolant % % 'fourier' % approximation using Fourier basis; nested nodes % Note: the quadrature induced by this rule is % constructed by integrating the interpolant % % Quadrature rules, the weights target exactness with respect to the % highest polynomial degree possible % % 'gauss-legendre' 'gauss-legendre-odd' % approximation using roots of polynomials orthogonal in % measure Uniform % % 'gauss-patterson' (a.k.a. nested Gauss-Legendre) % Note: the nodes and weights are hard-coded hence there % is a limit on the highest possible depth % Note: nestedness gives an interpolation rule % % 'gauss-chebyshev-1' 'gauss-chebyshev-1-odd' % 'gauss-chebyshev-2' 'gauss-chebyshev-2-odd' % approximation using roots of polynomials orthogonal in % measures 1/sqrt(1-x^2) and sqrt(1-x^2) (respectively) % % 'gauss-gegenbauer' 'gauss-gegenbauer-odd' % approximation using roots of polynomials orthogonal in % measure (1-x^2)^alpha % % 'gauss-jacobi' % approximation using roots of polynomials orthogonal in % measure (1-x)^alpha * (1+x)^beta % % 'gauss-laguerre' % approximation using roots of polynomials orthogonal in % measure x^alpha * epx(-x) % % 'gauss-hermite' 'gauss-hermite-odd' % approximation using roots of polynomials orthogonal in % measure |x|^alpha * epx(-x^2) % % Local rules (Note: the quadrature induced by those rules is % constructed by integrating the interpolant) % Note: local rules ignore the values of inputs sType, % vAnisotropy and vAlphaBeta % % 'localp' 'localp-zero' 'semilocalp' % local polynomials % % 'wavelet' % wavelets % % sType: (string giving the tensor selection strategy) % 'level' 'curved' 'tensor' 'iptensor' % 'iptotal' 'ipcurved' 'qptotal' 'qpcurved' % 'hyperbolic' 'iphyperbolic' 'qphyperbolic' % % iDepth: (integer non-negative) % controls the density of the grid, i.e., the offset for the tensor % selection, the meaning of iDepth depends on sType % Example 1: sType == 'iptotal' will give a grid that interpolates % exactly all polynomials of degree up to and including iDepth % Example 2: sType == 'qptotal' will give a grid that integrates % exactly all polynomials of degree up to and including iDepth % % iOrder: (integer for local polynomials iOrder must be -1 or bigger, for % wavelet quadrature iOrder must be either 1 or 3) % Note: iOrder is ignored for non-Local rules (see above) % % % mTransformAB: (optional matrix of size iDim x 2) % for all but gauss-laguerre and gauss-hermite grids, the % transform specifies the lower and upper bound of the domain % in each direction. For gauss-laguerre and gauss-hermite % grids, the transform gives the a and b parameters that % change the weight to % exp(-b (x - a)) and exp(-b (x - a)^2) % % vAnisotropy: (optional vector of positive integers, length iDim or 2*iDim) % the anisotropic weights associated with sType % % vAlphaBeta: (optional vector of length 1 or 2) % vAlphaBeta(1) is the alpha parameter for Gegenbauer, Jacobi, % Hermite and Laguerre rules % vAlphaBeta(2) is the beta parameter for Jacobi rules % % lCustomRule: (global grids of custom-tabulated rule) % custom_rule can be either of 3 things: % % string containing filename with a defined custom name % % structure containing the filed lCustomRule.sFilename, % which is the name of a file containing the user defined % rule % % structure defining the fields % lCustomRule.sDescription % lCustomRule.iMaxLevel % lCustomRule.vLevels % lCustomRule.vPrecision % lCustomRule.vNodes % lCustomRule.vWeights % % see help tsgWriteCustomRuleFile.m for definition of % each field of the structure % % sConformalMap: (optional string giving the type of transform) % conformal maps provide a non-linear domain transform, % approximation (quadrature or interpolation) is done % on the composition of f and the transform. A suitable % transform could reduce the error by as much as an % order of magnitude. % % 'asin': truncated MacLaurin series of arch-sin % % vConfromalWeights: (optional parameters for the conformal trnasform) % 'asin": indicate the number of terms to keep after % truncation % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D using % clenshaw-curtis rule, [1, 99] forces the grid to have % at most 3 possible values in the first variable and % ~2^99 (practicallyt infinite) number in the second % direction. vLimitLevels works in conjunction with % iDepth and sType, the points added to the grid will % obey both bounds % % OUTPUT: % % weights: the quadrature weights % NOTE: the weights associated with sparse grids are not always % positive. Futhermore, the weights associated with local rules % can have zero weights % % points: the quadrature nodes, i.e., quad(f) = weights' * f(points) % % [weights, points] = tsgMakeQuadrature(iDim, s1D, sType, iDepth, iOrder, % mTransformAB, vAlphaBeta, vAnisotropy, lCustomRule, % sConformalMap, vConfromalWeights, vLimitLevels) % [sFiles, sTasGrid] = tsgGetPaths(); lTempGrid.sName = ''; [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lTempGrid); sCommand = [sTasGrid,' -makequadrature']; bLocal = (strcmp(s1D, 'localp') || strcmp(s1D, 'wavelet') || strcmp(s1D, 'localp-zero') || strcmp(s1D, 'semilocalp')); sCommand = [sCommand, ' -dimensions ', num2str(iDim)]; sCommand = [sCommand, ' -onedim ', s1D]; sCommand = [sCommand, ' -depth ', num2str(iDepth)]; if (bLocal) sCommand = [sCommand, ' -order ', num2str(iOrder)]; else sCommand = [sCommand, ' -type ', sType]; % set anisotropy if (exist('vAnisotropy') && (max(size(vAnisotropy)) ~= 0)) if (min(size(vAnisotropy)) ~= 1) error(' vAnisotropy must be a vector, i.e., one row or one column'); end if (max(size(vAnisotropy)) ~= iDim) error(' vAnisotropy must be a vector of size iDim'); end if (size(vAnisotropy, 1) > size(vAnisotropy, 2)) tsgWriteMatrix(sFileW, vAnisotropy'); else tsgWriteMatrix(sFileW, vAnisotropy); end sCommand = [sCommand, ' -anisotropyfile ',sFileW]; end % set alpha and beta if (exist('vAlphaBeta') && (max(size(vAlphaBeta)) ~= 0)) if (min(size(vAlphaBeta)) ~= 1) error(' vAlphaBeta must be a vector, i.e., one row or one column'); end if (max(size(vAlphaBeta)) > 2) error(' vAlphaBeta must be a vector of size at most 2'); end sCommand = [sCommand, ' -alpha ',num2str(vAlphaBeta(1),16)]; if (max(size(vAlphaBeta)) > 1) sCommand = [sCommand, ' -beta ',num2str(vAlphaBeta(2),16)]; end end end % set the domain transformation if (exist('mTransformAB') && (max(size(mTransformAB)) ~= 0)) if (size(mTransformAB, 2) ~= 2) error(' mTransformAB must be a matrix with 2 columns'); end if (size(mTransformAB, 1) ~= iDim) error(' mTransformAB must be a matrix with iDim number of rows'); end tsgWriteMatrix(sFileV, mTransformAB); sCommand = [sCommand, ' -tf ',sFileV]; end % set custom rule if (strcmp(s1D, 'custom-tabulated')) if (exist('lCustomRule')) if (ischar(lCustomRule)) sCommand = [sCommand, ' -cf ', lCustomRule]; elseif (isfield(lCustomRule, 'filename')) % DEPRECATED syntax sCommand = [sCommand, ' -cf ', lCustomRule.filename]; elseif (isfield(lCustomRule, 'sFilename')) sCommand = [sCommand, ' -cf ', lCustomRule.sFilename]; else tsgWriteCustomRuleFile(sFileX, lCustomRule); sCommand = [sCommand, ' -cf ', sFileX]; end else disp(['ERROR: must provide a lCustomRule variable to use with a custom rule']); return; end end % set conformal mapping if (exist('sConformalMap') && (max(size(sConformalMap)) ~= 0)) if (~exist('vConfromalWeights')) error(' sConformalMap requires vConfromalWeights') end sCommand = [sCommand, ' -conformaltype ', sConformalMap]; if (size(vConfromalWeights, 1) > size(vConfromalWeights, 2)) tsgWriteMatrix(sFileC, vConfromalWeights'); else tsgWriteMatrix(sFileC, vConfromalWeights); end lClean.sFileC = 1; sCommand = [sCommand, ' -conformalfile ',sFileC]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end sCommand = [sCommand, ' -of ', sFileO]; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end end wp = tsgReadMatrix(sFileO); weights = wp(:,1); points = wp(:,2:end); % clean up after ourselves tsgDeleteGridByName(''); end TASMANIAN-8.1/InterfaceMATLAB/tsgMakeSequence.m000066400000000000000000000161551470551176200207400ustar00rootroot00000000000000function [lGrid, points] = tsgMakeSequence(sGridName, iDim, iOut, s1D, sType, iDepth, mTransformAB, vAnisotropy, sConformalMap, vConfromalWeights, vLimitLevels) % % [lGrid, points] % = tsgMakeSequence(sGridName, iDim, iOut, s1D, sType, iDepth, % mTransformAB, vAnisotropy, % sConformalMap, vConfromalWeights, vLimitLevels) % % creates a new sparse grid using a sequence rule % % INPUT: % % sGridName: the name of the grid, give it a string name, % i.e. 'myGrid' or '1' or 'pi314' % DO NOT LEAVE THIS EMPTY % % iDim: (integer, positive) % the number of inputs % % iOut: (integer, non-negative) % the number of outputs % % s1D: (string for the underlying 1-D rule that induces the grid) % % 'leja' 'rleja' 'rleja-shifted' % 'max-lebesgue' 'min-lebesgue' 'min-delta' % % sType: (string giving the tensor selection strategy) % 'level' 'curved' 'tensor' 'iptensor' % 'iptotal' 'ipcurved' 'qptotal' 'qpcurved' % 'hyperbolic' 'iphyperbolic' 'qphyperbolic' % % iDepth: (integer non-negative) % controls the density of the grid, i.e., the offset for the tensor % selection, the meaning of iDepth depends on sType % Example 1: sType == 'iptotal' will give a grid that interpolates % exactly all polynomials of degree up to and including iDepth % Example 2: sType == 'qptotal' will give a grid that integrates % exactly all polynomials of degree up to and including iDepth % % vAnisotropy: (optional vector of positive integers, length iDim or 2*iDim) % the anisotropic weights associated with sType % % mTransformAB: (optional matrix of size iDim x 2) % for all but gauss-laguerre and gauss-hermite grids, the % transform specifies the lower and upper bound of the domain % in each direction. For gauss-laguerre and gauss-hermite % grids, the transform gives the a and b parameters that % change the weight to % exp(-b (x - a)) and exp(-b (x - a)^2) % % sConformalMap: (optional string giving the type of transform) % conformal maps provide a non-linear domain transform, % approximation (quadrature or interpolation) is done % on the composition of f and the transform. A suitable % transform could reduce the error by as much as an % order of magnitude. % % 'asin': truncated MacLaurin series of arch-sin % % vConfromalWeights: (optional parameters for the conformal trnasform) % 'asin': indicate the number of terms to keep after % truncation % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D using % clenshaw-curtis rule, [1, 99] forces the grid to have % at most 3 possible values in the first variable and % ~2^99 (practicallyt infinite) number in the second % direction. vLimitLevels works in conjunction with % iDepth and sType, the points added to the grid will % obey both bounds % % OUTPUT: % % lGrid: list containing information about the sparse grid, can be used % to call other functions % % points: (optional) the points of the grid in an array % of dimension [num_poits, dim] % % [lGrid, points] % = tsgMakeSequence(sGridName, iDim, iOut, s1D, sType, iDepth, % mTransformAB, vAnisotropy, % sConformalMap, vConfromalWeights, vLimitLevels) % % create lGrid object lGrid.sName = sGridName; lGrid.sFilename = tsgMakeGridFilename(sGridName); lGrid.iDim = iDim; lGrid.iOut = iOut; lGrid.sType = 'sequence'; % check for conflict with tsgMakeQuadrature if (strcmp(sGridName, '')) error('sGridName cannot be empty'); end % generate filenames [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -makesequence']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -dimensions ', num2str(lGrid.iDim)]; sCommand = [sCommand, ' -outputs ', num2str(lGrid.iOut)]; sCommand = [sCommand, ' -onedim ', s1D]; sCommand = [sCommand, ' -depth ', num2str(iDepth)]; sCommand = [sCommand, ' -type ', sType]; % set the domain transformation if (exist('mTransformAB') && (max(size(mTransformAB)) ~= 0)) if (size(mTransformAB, 2) ~= 2) error(' mTransformAB must be a matrix with 2 columns'); end if (size(mTransformAB, 1) ~= lGrid.iDim) error(' mTransformAB must be a matrix with iDim number of rows'); end tsgWriteMatrix(sFileV, mTransformAB); lClean.sFileV = 1; sCommand = [sCommand, ' -tf ',sFileV]; end % set anisotropy if (exist('vAnisotropy') && (max(size(vAnisotropy)) ~= 0)) if (min(size(vAnisotropy)) ~= 1) error(' vAnisotropy must be a vector, i.e., one row or one column'); end if (max(size(vAnisotropy)) ~= lGrid.iDim) error(' vAnisotropy must be a vector of size iDim'); end if (size(vAnisotropy, 1) > size(vAnisotropy, 2)) tsgWriteMatrix(sFileW, vAnisotropy'); else tsgWriteMatrix(sFileW, vAnisotropy); end lClean.sFileW = 1; sCommand = [sCommand, ' -anisotropyfile ',sFileW]; end % set conformal mapping if (exist('sConformalMap') && (max(size(sConformalMap)) ~= 0)) if (~exist('vConfromalWeights')) error(' sConformalMap requires vConfromalWeights') end sCommand = [sCommand, ' -conformaltype ', sConformalMap]; if (size(vConfromalWeights, 1) > size(vConfromalWeights, 2)) tsgWriteMatrix(sFileC, vConfromalWeights'); else tsgWriteMatrix(sFileC, vConfromalWeights); end lClean.sFileC = 1; sCommand = [sCommand, ' -conformalfile ',sFileC]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= lGrid.iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end % read the points for the grid if (nargout > 1) sCommand = [sCommand, ' -of ',sFileO]; lClean.sFileO = 1; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end if (nargout > 1) points = tsgReadMatrix(sFileO); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgMakeWavelet.m000066400000000000000000000130331470551176200205670ustar00rootroot00000000000000function [lGrid, points] = tsgMakeWavelet(sGridName, iDim, iOut, iDepth, iOrder, mTransformAB, sConformalMap, vConfromalWeights, vLimitLevels) % % [lGrid, points] = tsgMakeWavelet(sGridName, iDim, iOut, iDepth, iOrder, % mTransformAB, sConformalMap, vConfromalWeights) % % creates a new sparse grid using a sequence rule % % INPUT: % % sGridName: the name of the grid, give it a string name, % i.e. 'myGrid' or '1' or 'pi314' % DO NOT LEAVE THIS EMPTY % % iDim: (integer, positive) % the number of inputs % % iOut: (integer, non-negative) % the number of outputs % % iDepth: (integer non-negative) % controls the density of the grid, i.e., the number of % levels to use % % iOrder: (integer must be 1 or 3) % note that only wavelets of order 1 and 3 are implemented % % mTransformAB: (optional matrix of size iDim x 2) % for all but gauss-laguerre and gauss-hermite grids, the % transform specifies the lower and upper bound of the domain % in each direction. For gauss-laguerre and gauss-hermite % grids, the transform gives the a and b parameters that % change the weight to % exp(-b (x - a)) and exp(-b (x - a)^2) % % sConformalMap: (optional string giving the type of transform) % conformal maps provide a non-linear domain transform, % approximation (quadrature or interpolation) is done % on the composition of f and the transform. A suitable % transform could reduce the error by as much as an % order of magnitude. % % 'asin': truncated MacLaurin series of arch-sin % % vConfromalWeights: (optional parameters for the conformal trnasform) % 'asin': indicate the number of terms to keep after % truncation % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D [1, 99] forces % the grid to have at most 3 possible values in the first % variable and ~2^99 (practicallyt infinite) number in the % second direction. vLimitLevels works in conjunction with % iDepth, for each direction, we chose the lesser of the % vLimitLevels and iDepth % % OUTPUT: % % lGrid: list containing information about the sparse grid, can be used % to call other functions % % points: (optional) the points of the grid in an array % of dimension [num_poits, dim] % % [lGrid, points] = tsgMakeWavelet(sGridName, iDim, iOut, iDepth, iOrder, % mTransformAB, sConformalMap, vConfromalWeights) % % create lGrid object lGrid.sName = sGridName; lGrid.sFilename = tsgMakeGridFilename(sGridName); lGrid.iDim = iDim; lGrid.iOut = iOut; lGrid.sType = 'wavelet'; % check for conflict with tsgMakeQuadrature if (strcmp(sGridName, '')) error('sGridName cannot be empty'); end % generate filenames [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -makewavelet']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -dimensions ', num2str(lGrid.iDim)]; sCommand = [sCommand, ' -outputs ', num2str(lGrid.iOut)]; sCommand = [sCommand, ' -depth ', num2str(iDepth)]; sCommand = [sCommand, ' -order ', num2str(iOrder)]; % set the domain transformation if (exist('mTransformAB') && (max(size(mTransformAB)) ~= 0)) if (size(mTransformAB, 2) ~= 2) error(' mTransformAB must be a matrix with 2 columns'); end if (size(mTransformAB, 1) ~= lGrid.iDim) error(' mTransformAB must be a matrix with iDim number of rows'); end tsgWriteMatrix(sFileV, mTransformAB); lGlean.sFileV = 1; sCommand = [sCommand, ' -tf ',sFileV]; end % set conformal mapping if (exist('sConformalMap') && (max(size(sConformalMap)) ~= 0)) if (~exist('vConfromalWeights')) error(' sConformalMap requires vConfromalWeights') end sCommand = [sCommand, ' -conformaltype ', sConformalMap]; if (size(vConfromalWeights, 1) > size(vConfromalWeights, 2)) tsgWriteMatrix(sFileC, vConfromalWeights'); else tsgWriteMatrix(sFileC, vConfromalWeights); end lClean.sFileC = 1; sCommand = [sCommand, ' -conformalfile ',sFileC]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= lGrid.iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end % read the points for the grid if (nargout > 1) sCommand = [sCommand, ' -of ',sFileO]; lGlean.sFileO = 1; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end if (nargout > 1) points = tsgReadMatrix(sFileO); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgMergeRefine.m000066400000000000000000000014041470551176200205510ustar00rootroot00000000000000function tsgMergeRefine(lGrid) % % tsgMergeRefine(lGrid) % % merges the points and loaded points and discards the loaded values % % INPUT: % % lGrid: a grid list created by tsgMake***(...) % % OUTPUT: % % The grid file associated with lGrid is modified % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -mergerefine']; sCommand = [sCommand, ' -gridfile ', sFileG]; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~ isempty(cmdout)) fprintf(1,['Warning: Command had non-empty output:\n']); disp(cmdout); end end end TASMANIAN-8.1/InterfaceMATLAB/tsgPlotPoints2D.m000066400000000000000000000013701470551176200206640ustar00rootroot00000000000000function tsgPlotPoints2D(points, fig) % % plotGrid2D(points, fig) % % plots two dimensional points in a figure % % INPUT: % % points: (matrix number_of_points X 2) % points created using tsgMakeXXX(...) command with iDim = 2 % % fig: (optional integer figure number) % the plot will show on the given figure % by default everything is plotted on figure 1 % if (nargin < 2) fig = 1; end if (size(points, 2) ~= 2) disp(['ERROR: size of q should be n by 2']); return end qm = min(points); qM = max(points); qD = (qM - qm); qI = 0.05 * qD; qm = qm - qI; qM = qM + qI; figure(fig) hold on for i = 1:size(points,1) pl = plot(points(i,1), points(i,2), '.'); set(pl, 'MarkerSize', 15); end axis([qm(1),qM(1),qm(2),qM(2)]); endTASMANIAN-8.1/InterfaceMATLAB/tsgReadCustomRuleFile.m000066400000000000000000000025421470551176200220630ustar00rootroot00000000000000function lCustomRule = tsgReadCustomRuleFile(sFilename) % % reads a custom-tabulated rule from an ASCII file % % description: Test CT % levels: 2 % 1 1 % 2 3 % 2.0 0.0 % 1.5 -0.5 % 0.5 0.5 % % results in the list with properties % % sDescription = 'Test CT' % iMaxLevel = 2 % vLevels = [1; 2] % vPrecision = [1; 3] % vNodes = [0.0, -0.5, 0.5] % vWeights = [2.0, 1.5, 0.5] % sFilename = regexprep(sFilename, '\\ ', ' '); fid = fopen(sFilename); sLine = fgetl(fid); if (strfind('description: ', sLine) ~= 1) error('Wrong file format of custom tabulated file on line 1!'); end lCustomRule.sDescription = strrep(sLine, 'description: ', ''); sLine = fgetl(fid); if (strfind('levels: ', sLine) ~= 1) error('Wrong file format of custom tabulated file on line 2!'); end lCustomRule.iMaxLevel = str2double(strrep(sLine, 'levels: ', '')); lCustomRule.vLevels = zeros(lCustomRule.iMaxLevel, 1); lCustomRule.vPrecision = zeros(lCustomRule.iMaxLevel, 1); for i=1:lCustomRule.iMaxLevel s = fscanf(fid, ' %f ', [1, 2]); lCustomRule.vLevels(i) = s(1); lCustomRule.vPrecision(i) = s(2); end lCustomRule.vNodes = zeros(sum(lCustomRule.vLevels), 1); lCustomRule.vWeights = zeros(sum(lCustomRule.vLevels), 1); for i=1:sum(lCustomRule.vLevels) s = fscanf(fid, ' %f ', [1, 2]); lCustomRule.vNodes(i) = s(2); lCustomRule.vWeights(i) = s(1); end fclose(fid); end TASMANIAN-8.1/InterfaceMATLAB/tsgReadMatrix.m000066400000000000000000000015501470551176200204230ustar00rootroot00000000000000function [mat] = tsgReadMatrix(filename) % % [mat] = tsgReadMatrix(filename) % % reads a matrix from a file format % % 3 4 % 1 2 3 4 % 5 6 7 8 % 9 10 11 12 % % results in the matrix [1 2 3 4; 5 6 7 8; 9 10 11 12;] % %disp(filename) filename = regexprep(filename, '\\ ', ' '); %disp(filename) fid = fopen(filename); TSG = fread(fid, [1, 3], '*char'); if (TSG == 'TSG') D = fread(fid, [1, 2], '*int'); Rows = D(1); Cols = D(2); mat = fread(fid, [Cols, Rows], '*double')'; fclose(fid); return; else fclose(fid); end % not binary format, keep this for old support fid = fopen(filename); [s] = fscanf(fid, ' %d ', [1, 2]); % load the number of points Ni = s(1); Nj = s(2); if ((Ni>0) && (Nj>0)) mat = zeros(Ni, Nj); else mat = []; end for i = 1:Ni [s] = fscanf(fid, ' %f ', [1, Nj]); mat(i,:) = s; end fclose(fid); end TASMANIAN-8.1/InterfaceMATLAB/tsgRefineAnisotropic.m000066400000000000000000000062021470551176200220050ustar00rootroot00000000000000function [new_points] = tsgRefineAnisotropic(lGrid, sType, iMinNew, iOut, vLimitLevels) % % [new_points] = tsgRefineAnisotropic(lGrid, sType, iMinNew, % iOut, vLimitLevels) % % computes anisotropic weights corresponding to sType and refines the grid % so that at least iMinNew points are added to the grid while respecting % the computed anisotropic weights % % NOTE: this can be called only for global and sequence grids % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % sType: (string giving the tensor selection strategy) % 'level' 'curved' 'tensor' 'iptensor' % 'iptotal' 'ipcurved' 'qptotal' 'qpcurved' % % iMinNew: (integer strictly positive) % minimum number of new points to include in the new grid % % iOut: (integer giving the output to be used for the refinement) % selects which output to use for refinement % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D using % clenshaw-curtis rule, [1, 99] forces the grid to have % at most 3 possible values in the first variable and % ~2^99 (practicallyt infinite) number in the second % direction. vLimitLevels overwrites iMinNew, if using % vLimitLevels the number of new points may be less than % iMinNew, increase iMinNew until a desired number of % points is selected % % OUTPUT: % % new_points: (optional) array % the new set of needed points % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -refineaniso']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -type ', sType]; sCommand = [sCommand, ' -ming ', num2str(iMinNew)]; if (exist('iOut')) sCommand = [sCommand, ' -refout ', num2str(iOut)]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= lGrid.iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end % read the points for the grid if (nargout == 1) sCommand = [sCommand, ' -of ',sFileO]; lClean.sFileO = 1; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end if (nargout == 1) [new_points] = tsgReadMatrix(sFileO); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgRefineSurplus.m000066400000000000000000000100741470551176200211720ustar00rootroot00000000000000function [new_points] = tsgRefineSurplus(lGrid, fTolerance, sRefinementType, iOut, vLimitLevels, mCorrection) % % [new_points] = tsgRefineSurplus(lGrid, fTolerance, sRefinementType, % iOut, vLimitLevels) % % adds new points to the grid in the neighbourhood of existing points % associated with large hierarchical surplus % % This function works for Local Polynomial and Wavelet grids only % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % fTolerance: (real non-negative number) % refine only in neighborhood of points that satisfy % max(point_surplus / max_value) > fTolerance % where max(...) is taken over all outputs % point_surplus is the hierarchical surplus % max_value is the largest loaded value associated with each output % % % sRefinementType: (string indicating the refinement type) % 'classic' 'parents' 'direction' 'fds' 'stable' % only for Local Polynomial and Wavelet grids % % iOut: (integer giving the output to be used for the refinement) % selects which output to use for refinement, must be specified for % Global Grids, other grid can omit this or set it to [] to indicate % the use of all outputs % % vLimitLevels: (optional vector of integers of size iDim) % limit the level in each direction, no points beyond the % specified limit will be used, e.g., in 2D using % localp rule, [1, 99] forces the grid to have % at most 3 possible values in the first variable and % ~2^99 (practicallyt infinite) number in the second % direction. % % mCorrection: (optional matrix with size num_points by num_outputs or 1) % the surpluses in the refinement procedure will be multiplied % by the correction % if iOut is -1, then one weight must be given per output and % the columns must match the number of outputs % if iOut is specified, mCorrection must have one column % % OUTPUT: % % new_points: (optional) array % the new set of needed points % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC, sFileL] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -refinesurp']; sCommand = [sCommand, ' -gridfile ', sFileG]; sCommand = [sCommand, ' -tolerance ', num2str(fTolerance,17)]; if ((exist('sRefinementType')) && (max(size(sRefinementType)) ~= 0)) sCommand = [sCommand, ' -reftype ', sRefinementType]; end if (exist('iOut') && (max(size(iOut)) ~= 0)) sCommand = [sCommand, ' -refout ', num2str(iOut)]; end % set level limits if (exist('vLimitLevels') && (max(size(vLimitLevels)) ~= 0)) if (min(size(vLimitLevels)) ~= 1) error(' vLimitLevels must be a vector, i.e., one row or one column'); end if (max(size(vLimitLevels)) ~= lGrid.iDim) error(' vLimitLevels must be a vector of size iDim'); end if (size(vLimitLevels, 1) > size(vLimitLevels, 2)) tsgWriteMatrix(sFileL, vLimitLevels'); else tsgWriteMatrix(sFileL, vLimitLevels); end lClean.sFileL = 1; sCommand = [sCommand, ' -levellimitsfile ', sFileL]; end % set correction if (exist('mCorrection') && (max(size(mCorrection)) ~= 0)) if (min(size(mCorrection)) ~= 1) error(' mCorrection must be a vector, i.e., one row or one column'); end tsgWriteMatrix(sFileV, mCorrection); lClean.sFileV = 1; sCommand = [sCommand, ' -valsfile ', sFileV]; end % read the points for the grid if (nargout == 1) sCommand = [sCommand, ' -of ',sFileO]; lClean.sFileO = 1; end [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else if (~isempty(cmdout)) fprintf(1,['WARNING: Command had non-empty output:\n']); disp(cmdout); end if (nargout == 1) [new_points] = tsgReadMatrix(sFileO); end end if (exist('lClean')) tsgCleanTempFiles(lGrid, lClean); end end TASMANIAN-8.1/InterfaceMATLAB/tsgReloadGrid.m000066400000000000000000000034111470551176200203750ustar00rootroot00000000000000function [lGrid] = tsgReloadGrid(sGridName) % % [lGrid] = tsgReloadGrid(sGridName) % % Searches through the work files for files corresponding to a grid with % name sName, then creates a new lGrid object associated with the grid. % % Note: this does not check if there are already other lGrid objects % associated with the name, aliasing can cause issues here. % % INPUT: % % sGridName: name of a grid that exists in the work files % % OUTPUT: % % lGrid: list containing information about the sparse grid, can be used to % call other functions % [sFiles, sTasGrid] = tsgGetPaths(); lTempGrid.sName = sGridName; [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lTempGrid); % try the old way sTestFile = regexprep(sFileG, '\\ ', ' '); if (exist(sTestFile, 'file') ~= 2) lTempGrid.sName = sGridName; lTempGrid.sFilename = tsgMakeGridFilename(sGridName); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lTempGrid); sTestFile = regexprep(sFileG, '\\ ', ' '); if (exist(sTestFile, 'file') ~= 2) error(['There is no grid named: ',sGridName]); end end sCommand = [sTasGrid,' -summary -gridfile ', sFileG]; [status, cmdout] = system(sCommand); sLines = strsplit(cmdout, {'\n','\r'}); l1 = strsplit(sLines{2}); l2 = strsplit(sLines{3}); l3 = strsplit(sLines{4}); % create lGrid object lGrid.sName = sGridName; lGrid.sFilename = sFileG; if (strcmp(l1{4}, 'Global')) lGrid.sType = 'global'; elseif (strcmp(l1{4}, 'Sequence')) lGrid.sType = 'sequence'; elseif (strcmp(l1{4}, 'Local')) lGrid.sType = 'localpolynomial'; elseif (strcmp(l1{4}, 'Wavelets')) lGrid.sType = 'wavelet'; elseif (strcmp(l1{4}, 'Fourier')) lGrid.sType = 'fourier'; end lGrid.iDim = str2num(l2{3}); lGrid.iOut = str2num(l3{3}); end TASMANIAN-8.1/InterfaceMATLAB/tsgSummary.m000066400000000000000000000012241470551176200200160ustar00rootroot00000000000000function tsgSummary(lGrid) % % tsgSummary(lGrid) % % prints human readable summary of the grid properties % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % OUTPUT: % % Text is printed out % Note: lGrid is NOT modified by this command % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -summary']; sCommand = [sCommand, ' -gridfile ', sFileG]; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else disp(cmdout); end end TASMANIAN-8.1/InterfaceMATLAB/tsgUsingConstruction.m000066400000000000000000000015731470551176200220700ustar00rootroot00000000000000function [ result ] = tsgUsingConstruction(lGrid) % % tsgUsingConstruction(lGrid) % % return 0/1 indicating whether dynamic construction is enabled % corresponds to TasmanianSparseGrid::isUsingConstruction() % % INPUT: % % lGrid: a grid list created by tsgMakeXXX(...) % % OUTPUT: % % result will be either 1 if the dynamic construction has been enabled % or 0 if not enabled % Note: lGrid is NOT modified by this command % [sFiles, sTasGrid] = tsgGetPaths(); [sFileG, sFileX, sFileV, sFileO, sFileW, sFileC] = tsgMakeFilenames(lGrid); sCommand = [sTasGrid,' -using-construct']; sCommand = [sCommand, ' -gridfile ', sFileG]; [status, cmdout] = system(sCommand); if (max(size(strfind(cmdout, 'ERROR'))) ~= 0) disp(cmdout); error('The tasgrid execurable returned an error, see above'); return; else result = (norm( size(strfind(cmdout, 'enabled')) ) > 0); end end TASMANIAN-8.1/InterfaceMATLAB/tsgWriteCustomRuleFile.m000066400000000000000000000052271470551176200223050ustar00rootroot00000000000000function tsgWriteCustomRuleFile(sFilename, lCustomRule) % % tsgWriteCustomRuleFile(sFilename, lCustomRule) % % uses the custom rule specified by the lCustomRule variable and writes % it into a file with the given filename % % INPUT: % % sFilename: the file where the custom rule should be written % % lCustomRule: % the customRule structure that specifies the rule % % lCustomRule.sDescription: % the string describing the rule (for user information purposes only) % % lCustomRule.iMaxLevel: % the number (integer) of levels defined by the rule % % lCustomRule.vLevels: % a vector of length lCustomRule.iMaxLevel (integers) % defines the number of points on each level % % lCustomRule.vPrecision: % a vector of length lCustomRule.iMaxLevel (integers) % defines the precision (in polynomial order) or each level of the % quadrature rule, e.g., for Gauss-Legendre rule % custom_rule.precision = 2*custom_rule.levels-1 % NOTE: grids of type other than ip* and qp* will ignore the % precision, in which case, precision can be set to a % vector of zeros % % lCustomRule.vNodes: % a vector of length sum(lCustomRule.vLevels) (floats) % for each level in order, defines the abscissas of the custom rule % % lCustomRule.vWeights: % a vector of length sum(lCustomRule.vLevels) (floats) % for each level in order, defines the weights of the custom rule % corresponding the lCustomRule.vNodes % % OUTPUT: % a file is created with the custom rule % sFilename = regexprep(sFilename, '\\ ', ' '); fid = fopen(sFilename, 'w'); if (isfield(lCustomRule, 'sDescription')) sDesc = ['description: ', lCustomRule.sDescription,'\n']; else sDesc = ['description: ', lCustomRule.description,'\n']; end fprintf(fid, sDesc); if (isfield(lCustomRule, 'iMaxLevel')) sLevels = ['levels: ',num2str(lCustomRule.iMaxLevel),'\n']; else sLevels = ['levels: ',num2str(lCustomRule.max_level),'\n']; end fprintf(fid, sLevels); if (isfield(lCustomRule, 'vLevels')) for i = 1:lCustomRule.iMaxLevel fprintf(fid, '%d %d\n', [lCustomRule.vLevels(i), lCustomRule.vPrecision(i)]); end else for i = 1:lCustomRule.max_level fprintf(fid, '%d %d\n', [lCustomRule.levels(i), lCustomRule.precision(i)]); end end if (isfield(lCustomRule, 'vWeights')) for i = 1:sum(lCustomRule.vLevels) fprintf(fid, '%2.20e %2.20e\n', [lCustomRule.vWeights(i), lCustomRule.vNodes(i)]); end else for i = 1:sum(lCustomRule.levels) fprintf(fid, '%2.20e %2.20e\n', [lCustomRule.weights(i), lCustomRule.nodes(i)]); end end fclose(fid); end TASMANIAN-8.1/InterfaceMATLAB/tsgWriteMatrix.m000066400000000000000000000017371470551176200206510ustar00rootroot00000000000000function tsgWriteMatrix(filename, mat) % % tsgWriteMatrix(filename, mat) % % write a matrix to a text file % % the matrix [1 2 3 4; 5 6 7 8; 9 10 11 12;] % % is written as % % 3 4 % 1 2 3 4 % 5 6 7 8 % 9 10 11 12 % filename = regexprep(filename, '\\ ', ' '); if (prod(size(mat)) < 1000) % small matrix, use ascii format fid = fopen(filename, 'w'); fprintf(fid, '%d %d\n', size(mat, 1), size(mat, 2)); % load the number of points %format long; Ni = size(mat, 1); Nj = size(mat, 2); fmt = ['']; for i = 1:Nj fmt = [fmt, '%2.20e ']; end fmt = [fmt(1:end-1), '\n']; for i = 1:Ni fprintf(fid, fmt, mat(i,:)); end fclose(fid); else fid = fopen(filename, 'wb'); Ni = size(mat, 1); Nj = size(mat, 2); fwrite(fid, ['TSG']); fwrite(fid, [Ni, Nj], 'integer*4'); fwrite(fid, mat', 'double'); %if (size(mat, 1) > 10) % size(mat) % mat(1:10, :) %end fclose(fid); end end TASMANIAN-8.1/InterfacePython/000077500000000000000000000000001470551176200160075ustar00rootroot00000000000000TASMANIAN-8.1/InterfacePython/CMakeLists.txt000066400000000000000000000367711470551176200205650ustar00rootroot00000000000000######################################################################## # Python module, examples and tests # # Configure the .in. files using three stage configuration # stage 1: everything (build, test, etc) should work in the build folder # stage 2: everything should work after make install # ######################################################################## if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(Tasmanian_python_default_path "${CMAKE_INSTALL_PREFIX}/python${Python_VERSION_MAJOR}${Python_VERSION_MINOR}/site-packages") else() set(Tasmanian_python_default_path "${CMAKE_INSTALL_PREFIX}/lib/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages") endif() if (NOT "${Tasmanian_python_install_path}" STREQUAL "${Tasmanian_python_default_path}") set(Tasmanian_python_install_path "${Tasmanian_python_default_path}" CACHE INTERNAL "install path for the Python module (version specific)" FORCE) set(Tasmanian_PYTHONPATH "${CMAKE_INSTALL_PREFIX}/share/Tasmanian/python/" CACHE PATH "install path for the Python module (version independent)" FORCE) endif() # CMake has permissive implementation of boolean true, which includes # "On", "True" and "Yes" with different cases; # Here we convert boolen true to "ON" so it can # be safely passed to Python as a string and interpreted via # python_boolean = ("@cmake_boolean@" == "ON") foreach(_tsg_opt Tasmanian_ENABLE_BLAS Tasmanian_ENABLE_CUDA Tasmanian_ENABLE_HIP Tasmanian_ENABLE_DPCPP) if (${_tsg_opt}) set(${_tsg_opt} "ON") endif() endforeach() unset(_tsg_opt) ######################################################################## # Stage 1: Build folder paths ######################################################################## set(Tasmanian_string_python_hashbang "${Python_EXECUTABLE}") if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") # windows puts the temp .dll files in Release or Debug subfolder, as opposed to directly in ${CMAKE_CURRENT_BINARY_DIR} # add different configure file for each build type and copy the appropriate one with a custom command foreach(_tsg_configtype Release Debug) set(Tasmanian_libsparsegrid_path "${CMAKE_CURRENT_BINARY_DIR}/../SparseGrids/${_tsg_configtype}/${CMAKE_SHARED_LIBRARY_PREFIX}tasmaniansparsegrid${CMAKE_SHARED_LIBRARY_SUFFIX}") set(Tasmanian_libdream_path "${CMAKE_CURRENT_BINARY_DIR}/../DREAM/${_tsg_configtype}/${CMAKE_SHARED_LIBRARY_PREFIX}tasmaniandream${CMAKE_SHARED_LIBRARY_SUFFIX}") set(Tasmanian_libcaddons_path "${CMAKE_CURRENT_BINARY_DIR}/../Addons/${_tsg_configtype}/${CMAKE_SHARED_LIBRARY_PREFIX}tasmaniancaddons${CMAKE_SHARED_LIBRARY_SUFFIX}") # all libraries that are needed transitively must be included here, currently on the sparse grid library is needed set(Tasmanian_libpaths "${CMAKE_CURRENT_BINARY_DIR}/../SparseGrids/${_tsg_configtype}/") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/testConfigureData.in.py" "${CMAKE_CURRENT_BINARY_DIR}/testConfigureData${_tsg_configtype}.py") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/TasmanianConfig.in.py" "${CMAKE_CURRENT_BINARY_DIR}/TasmanianConfig${_tsg_configtype}.py") list(APPEND Tasmanian_python_files "${CMAKE_CURRENT_BINARY_DIR}/testConfigureData${_tsg_configtype}.py" "${CMAKE_CURRENT_BINARY_DIR}/TasmanianConfig${_tsg_configtype}.py") endforeach() unset(_tsg_configtype) add_custom_target(Tasmanian_python_interface ALL DEPENDS ${Tasmanian_python_files}) unset(Tasmanian_python_files) add_custom_command(TARGET Tasmanian_python_interface PRE_BUILD COMMAND "${CMAKE_COMMAND}" ARGS -E copy ${CMAKE_CURRENT_BINARY_DIR}/TasmanianConfig$.py ${CMAKE_CURRENT_BINARY_DIR}/TasmanianConfig.py COMMENT "Copying Python module for config $") add_custom_command(TARGET Tasmanian_python_interface PRE_BUILD COMMAND "${CMAKE_COMMAND}" ARGS -E copy ${CMAKE_CURRENT_BINARY_DIR}/testConfigureData$.py ${CMAKE_CURRENT_BINARY_DIR}/testConfigureData.py COMMENT "Copying Python module for config $") else() set(Tasmanian_libsparsegrid_path "${CMAKE_CURRENT_BINARY_DIR}/../SparseGrids/${CMAKE_SHARED_LIBRARY_PREFIX}tasmaniansparsegrid${CMAKE_SHARED_LIBRARY_SUFFIX}") set(Tasmanian_libdream_path "${CMAKE_CURRENT_BINARY_DIR}/../DREAM/${CMAKE_SHARED_LIBRARY_PREFIX}tasmaniandream${CMAKE_SHARED_LIBRARY_SUFFIX}") set(Tasmanian_libcaddons_path "${CMAKE_CURRENT_BINARY_DIR}/../Addons/${CMAKE_SHARED_LIBRARY_PREFIX}tasmaniancaddons${CMAKE_SHARED_LIBRARY_SUFFIX}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/testConfigureData.in.py" "${CMAKE_CURRENT_BINARY_DIR}/testConfigureData.py") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/TasmanianConfig.in.py" "${CMAKE_CURRENT_BINARY_DIR}/TasmanianConfig.py") endif() set(Tasmanian_python_example_import "sys.path.append(\"${CMAKE_CURRENT_BINARY_DIR}\")\n") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/example_sparse_grids.in.py" "${CMAKE_CURRENT_BINARY_DIR}/example_sparse_grids.py") # also uses Tasmanian_string_python_hashbang configure_file("${CMAKE_CURRENT_SOURCE_DIR}/example_dream.in.py" "${CMAKE_CURRENT_BINARY_DIR}/example_dream.py") # also uses Tasmanian_string_python_hashbang configure_file("${CMAKE_CURRENT_SOURCE_DIR}/example_optimization.in.py" "${CMAKE_CURRENT_BINARY_DIR}/example_optimization.py") # also uses Tasmanian_string_python_hashbang configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sandbox.py" "${CMAKE_CURRENT_BINARY_DIR}/sandbox.py") # only uses Tasmanian_string_python_hashbang configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../SparseGrids/GaussPattersonRule.table" "${CMAKE_CURRENT_BINARY_DIR}/GaussPattersonRule.table" COPYONLY) # needed for testing # See the matlab CMakeText.txt on how to copy multiple scripts set(Tasmanian_python_test_files TasmanianSG.py TasmanianAddons.py Tasmanian.py TasmanianDREAM.py TasmanianDreamLikely.py TasmanianDreamState.py TasmanianDreamSampler.py TasmanianOPT.py TasmanianParticleSwarm.py TasmanianGradientDescent.py testTSG.py testCommon.py testBasicIO.py testAcceleration.py testExceptions.py testMakeUpdate.py testRefinement.py testUnstructuredData.py testMisc.py testAddons.py testDream.py testOptimization.py example_sparse_grids_01.py example_sparse_grids_02.py example_sparse_grids_03.py example_sparse_grids_04.py example_sparse_grids_05.py example_sparse_grids_06.py example_sparse_grids_07.py example_sparse_grids_08.py example_sparse_grids_09.py example_sparse_grids_10.py example_sparse_grids_11.py example_dream_01.py example_dream_02.py example_dream_03.py example_dream_04.py example_dream_05.py example_optimization_01.py example_optimization_02.py ) foreach(Tasmanian_python_testing_file ${Tasmanian_python_test_files}) add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${Tasmanian_python_testing_file}" COMMAND "${CMAKE_COMMAND}" ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${Tasmanian_python_testing_file} ${CMAKE_CURRENT_BINARY_DIR}//${Tasmanian_python_testing_file} DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${Tasmanian_python_testing_file}" COMMENT "Copying ${CMAKE_CURRENT_SOURCE_DIR}/${Tasmanian_python_testing_file}") list(APPEND Tasmanian_python_testing_files_stage1 "${CMAKE_CURRENT_BINARY_DIR}/${Tasmanian_python_testing_file}") endforeach() unset(Tasmanian_python_testing_file) add_custom_target(Tasmanian_python_testing ALL DEPENDS "${Tasmanian_python_testing_files_stage1}") ######################################################################## # Stage 2: Install folder paths ######################################################################## set(Tasmanian_shared_lib_destination "lib") if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") # windows puts the .dll files in bin, as opposed to lib set(Tasmanian_shared_lib_destination "bin") endif() set(Tasmanian_libsparsegrid_path "${Tasmanian_final_install_path}/${Tasmanian_shared_lib_destination}/${CMAKE_SHARED_LIBRARY_PREFIX}tasmaniansparsegrid${CMAKE_SHARED_LIBRARY_SUFFIX}") set(Tasmanian_libdream_path "${Tasmanian_final_install_path}/${Tasmanian_shared_lib_destination}/${CMAKE_SHARED_LIBRARY_PREFIX}tasmaniandream${CMAKE_SHARED_LIBRARY_SUFFIX}") set(Tasmanian_libcaddons_path "${Tasmanian_final_install_path}/${Tasmanian_shared_lib_destination}/${CMAKE_SHARED_LIBRARY_PREFIX}tasmaniancaddons${CMAKE_SHARED_LIBRARY_SUFFIX}") set(Tasmanian_libpaths "${Tasmanian_final_install_path}/bin/") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/TasmanianConfig.in.py" "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianConfig.py") set(Tasmanian_python_example_import "sys.path.append(\"${Tasmanian_python_install_path}\")\n") if (SKBUILD) set(Tasmanian_python_example_import "") # if installed through pip, no path is needed endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/example_sparse_grids.in.py" "${CMAKE_CURRENT_BINARY_DIR}/configured/example_sparse_grids.py") # also uses Tasmanian_string_python_hashbang configure_file("${CMAKE_CURRENT_SOURCE_DIR}/example_dream.in.py" "${CMAKE_CURRENT_BINARY_DIR}/configured/example_dream.py") # also uses Tasmanian_string_python_hashbang configure_file("${CMAKE_CURRENT_SOURCE_DIR}/example_optimization.in.py" "${CMAKE_CURRENT_BINARY_DIR}/configured/example_optimization.py") # also uses Tasmanian_string_python_hashbang ######################################################################## # Testing ######################################################################## add_test(NAME PythonIO COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testBasicIO) add_test(NAME PythonAcceleration COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testAcceleratedEvaluate) add_test(NAME PythonExceptions COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testBasicException) add_test(NAME PythonMakeUpdate COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testAMakeUpdate) add_test(NAME PythonRefine COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testBRefinement) add_test(NAME PythonLearning COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testCUnsructuredData) add_test(NAME PythonMisc COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testZMisc) add_test(NAME PythonAddons COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testAddons) add_test(NAME PythonDream COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testDream) add_test(NAME PythonOptimization COMMAND Python::Interpreter "${CMAKE_CURRENT_BINARY_DIR}/testTSG.py" TestTasmanian.testOptimization) set_tests_properties(PythonIO PROPERTIES RUN_SERIAL ON) # IO and Refine read/write to potentially the same files set_tests_properties(PythonRefine PROPERTIES RUN_SERIAL ON) Tasmanian_set_test_properties(TESTS PythonIO PythonAcceleration PythonExceptions PythonMakeUpdate PythonRefine PythonLearning PythonMisc PythonAddons PythonDream) ######################################################################## # Windows system paths ######################################################################## if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(Tasmanian_MSVC_PATH_STRING "${CMAKE_CURRENT_BINARY_DIR}/../SparseGrids/Release;${CMAKE_CURRENT_BINARY_DIR}/../SparseGrids/Debug") set(Tasmanian_MSVC_PATH_STRING "${Tasmanian_MSVC_PATH_STRING};${CMAKE_CURRENT_BINARY_DIR}/../DREAM/Release;${CMAKE_CURRENT_BINARY_DIR}/../DREAM/Debug") set(Tasmanian_MSVC_PATH_STRING "${Tasmanian_MSVC_PATH_STRING};${CMAKE_CURRENT_BINARY_DIR}/../Addons/Release;${CMAKE_CURRENT_BINARY_DIR}/../Addons/Debug;$ENV{PATH}") string(REPLACE ";" "\\;" Tasmanian_MSVC_PATH_STRING "${Tasmanian_MSVC_PATH_STRING}") set_tests_properties(PythonIO PythonAcceleration PythonExceptions PythonMakeUpdate PythonRefine PythonLearning PythonMisc PythonAddons PythonDream PROPERTIES ENVIRONMENT "PATH=${Tasmanian_MSVC_PATH_STRING}") endif() ######################################################################## # Installation ######################################################################## macro(Tasmanian_python_install) cmake_parse_arguments(_tsg_py "" "" "FILES" ${ARGN}) foreach(_tsg_py_file ${_tsg_py_FILES}) get_filename_component(_tsg_py_name ${_tsg_py_file} NAME) # install in the version specific site-package location install(FILES ${_tsg_py_file} DESTINATION "${Tasmanian_python_install_path}" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) # install in the version independent location (note that pip-install doesn't handle sym-links) install(FILES ${_tsg_py_file} DESTINATION "${Tasmanian_PYTHONPATH}" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows" AND Tasmanian_windows_virtual) # windows virtual environments use a different path and naming convention, annoying ... install(FILES ${_tsg_py_file} DESTINATION "${CMAKE_INSTALL_PREFIX}/Lib/site-packages/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND Tasmanian_osx_framework) install(FILES ${_tsg_py_file} DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/python/site-packages/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) endif() endforeach() endmacro(Tasmanian_python_install) Tasmanian_python_install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianSG.py" "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianAddons.py" "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianDREAM.py" "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianDreamLikely.py" "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianDreamState.py" "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianDreamSampler.py" "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianOPT.py" "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianParticleSwarm.py" "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianGradientDescent.py" "${CMAKE_CURRENT_BINARY_DIR}/configured/TasmanianConfig.py" "${CMAKE_CURRENT_SOURCE_DIR}/Tasmanian.py") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" DESTINATION "share/Tasmanian/examples/" FILES_MATCHING PATTERN "example_*.py" PATTERN "*.in.*" EXCLUDE PATTERN "*PipInstaller*" EXCLUDE PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured/example_sparse_grids.py" "${CMAKE_CURRENT_BINARY_DIR}/configured/example_dream.py" "${CMAKE_CURRENT_BINARY_DIR}/configured/example_optimization.py" DESTINATION "share/Tasmanian/examples/" PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) TASMANIAN-8.1/InterfacePython/PipInstaller/000077500000000000000000000000001470551176200204155ustar00rootroot00000000000000TASMANIAN-8.1/InterfacePython/PipInstaller/MANIFEST.in000066400000000000000000000006561470551176200221620ustar00rootroot00000000000000include setup.py include pyproject.toml include CMakeLists.txt include LICENSE include *.md recursive-include Addons * recursive-include Config * recursive-include Doxygen * recursive-include DREAM * recursive-include InterfaceFortran * recursive-include InterfaceMATLAB * recursive-include InterfacePython * recursive-include InterfaceTPL * recursive-include SparseGrids * recursive-include Tasgrid * recursive-include Testing * TASMANIAN-8.1/InterfacePython/PipInstaller/README.md000066400000000000000000000103461470551176200217000ustar00rootroot00000000000000# Python PIP The latest stable release of Tasmanian is included in Pip: [https://pypi.org/project/Tasmanian/](https://pypi.org/project/Tasmanian/) This folder contains the setup files needed to build the Tasmanian pip archive, i.e., the source distribution `sdist` package. ### Quick Install Tasmanian supports installs under Linux, Max OSX, and Windows using Python 3 and either user or virtual environment installation. * if using an pip before 1.10 then must first install the build dependencies: ``` python3 -m pip install scikit-build cmake packaging numpy ``` * then perform either a user install ``` python3 -m pip install Tasmanian --user ``` * or virtual environment install ``` python3 -m pip install Tasmanian ``` If the installer is run more than once, the `--no-cache-dir` can be helpful to force repeating the CMake configuration process and thus clean any errors or obsolete settings in cache. ### Requirements The following Python modules are required: ``` setuptools version compatible with scikit-build wheel version compatible with scikit-build packaging version containing packaging.version.LegacyVersion scikit-build version >= 0.10.0 cmake version >= 3.19 (see the top of CMakeLists.txt) numpy version >= 1.10 ``` The `scikit-build` package is responsible for turning the CMake build system into one compatible with `pip`. The rest of the dependencies are there to facilitate the build process and only `numpy` is required at runtime. However, `pip` cannot automatically install build dependencies and hence these have to be installed beforehand. The process will require a compatible C++ compiler, make sure to have installed * Linux: `build-essential` with `g++` or the equivalent for the corresponding distribution * MacOSX: `xcode` or `gcc` * Windows: MS Visual Studio ### Quick Build Offline Commands to build the package: ``` cd bash ./InterfacePython/PipInstaller/make_tarball.sh python3 setup.py sdist ``` At this point, the `dist/Tasmanian-.tar.gz` package file will be created. xcode The package can be installed off-line, e.g., ``` python3 -m pip install dist/Tasmanian-.tar.gz --user ``` ### Dependencies * According to [PEP518](https://www.python.org/dev/peps/pep-0518/), the `pyproject.toml` file must specify the dependencies that are needed to run the `setup.py` script, e.g., scikit-build and packaging. * The `setup_requires` list in the `setup.py` script specifies the dependencies for the build process, e.g., make. * The `install_requires` list in the `setup.py` script specifies the run-time dependencies, e.g., numpy. ### Options Pip accepts both `--global-option=` and `--install-option=` parameters and scikit-build will automatically translate some of those into corresponding CMake commands. However, some python distributions (e.g., Ubuntu) deliberately ignore the options, not sure about the reason behind that, perhaps to limit breaks due to incorrect user-provided install paths. As an alternative, when using Pip, Tasmanian will accept environmental variables to setup BLAS, CUDA, MAGAM, MPI, and MATLAB options. ### Behind the Curtains The `pip` installer will execute the following steps: * un-tar the files into a temporary folder * build Tasmanian (out-of-source) using CMake * sci-kit will attempt to download and/or compile missing dependencies, e.g., compilers, CUDA and CMake * install Tasmanian to another temporary folder * copy all installed files to /.local or another relevant location * delete the temporary folders Currently Tasmanian has three shared libraries and they find each other through `rpath`, i.e., without the need to be added to the global library path. This necessitates the usage of `Tasmanian_final_install_path` which is usually the same as `CMAKE_INSTALL_PREFIX` except when working with `pip`, in which case the `rpath` is set to the final install path, e.g., `/.local`. The `setup.py` file sets the CMake options and predicts the install path. General information is also set here. The `MANIFEST.in` describes the source files that need to be added to the package tarball. Some files, such as `.gitignore`, `install` and `Makefile` are simply not needed by `pip` and are omitted deliberately. TASMANIAN-8.1/InterfacePython/PipInstaller/make_tarball.sh000066400000000000000000000007301470551176200233670ustar00rootroot00000000000000 this_folder=`pwd` if [ ! -d "$this_folder/SparseGrids/" ] || [ ! -d "$this_folder/InterfacePython/" ]; then echo "ERROR: must run this script from the Tasmanian source root folder" exit 1 fi cp ./InterfacePython/PipInstaller/setup.py . cp ./InterfacePython/PipInstaller/MANIFEST.in . cp ./InterfacePython/PipInstaller/pyproject.toml . python3 setup.py sdist rm MANIFEST.in rm MANIFEST rm pyproject.toml rm setup.py echo "tarball build in $this_folder/dist/" TASMANIAN-8.1/InterfacePython/PipInstaller/pyproject.toml000066400000000000000000000001271470551176200233310ustar00rootroot00000000000000[build-system] requires = ["setuptools", "wheel", "scikit-build>=0.10.0", "packaging"] TASMANIAN-8.1/InterfacePython/PipInstaller/setup.py000066400000000000000000000060401470551176200221270ustar00rootroot00000000000000 import sys, site # do standard skbuild setup from packaging import version from skbuild.exceptions import SKBuildError from skbuild.cmaker import get_cmake_version from skbuild import setup # This line replaces 'from setuptools import setup' # Add CMake as a build requirement if cmake is not installed or too old setup_requires = [] try: if version.parse(get_cmake_version()) < version.parse("3.19"): setup_requires.append('cmake>=3.19') except SKBuildError: setup_requires.append('cmake>=3.19') setup_requires.append('numpy>=1.10') with open('README.md', 'r') as fh: readme_file = fh.readlines() long_description = "" for line in readme_file[3:]: if line.rstrip() == "Quick Install": break else: long_description += line long_description += "### Quick Install\n Tasmanian supports `--user` and venv install only, see the on-line documentation for details.\n" # find out whether this is a virtual environment, real_prefix is an older test, base_refix is the newer one if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix): final_install_path = sys.prefix # sys.prefix points to the virtual environment root isvirtual = True else: isvirtual = False try: final_install_path = site.getuserbase() except: import os # some implementations do not provide compatible 'site' package, assume default Linux behavior final_install_path = os.getenv('HOME') + "/.local/" # check if using OSX Framework environment isosxframework = False if sys.platform == 'darwin': try: if 'python/site-packages' in site.getusersitepackages(): # appears to be Mac Framework using Library/Python/X.Y/lib/python/site-packages isosxframework = True except: # cannot determine if using Mac Framework pass # setup cmake arguments cmake_args=[ '-DCMAKE_BUILD_TYPE=Release', '-DBUILD_SHARED_LIBS=ON', '-DTasmanian_ENABLE_RECOMMENDED:BOOL=ON', '-DTasmanian_ENABLE_PYTHON:BOOL=ON', '-DPython_EXECUTABLE:PATH={0:1s}'.format(sys.executable), '-DTasmanian_python_pip_final:PATH={0:1s}/'.format(final_install_path), ] if isvirtual: cmake_args.append('-DTasmanian_windows_virtual:BOOL=ON') if isosxframework: cmake_args.append('-DTasmanian_osx_framework:BOOL=ON') # call the actual package setup command setup( name='Tasmanian', version='8.1', author='Miroslav Stoyanov', author_email='stoyanovmk@ornl.gov', description='UQ library for sparse grids, optimization and Bayesian inference', long_description=long_description, long_description_content_type="text/markdown", url='https://tasmanian.ornl.gov', classifiers=[ 'Programming Language :: Python :: 3', 'Programming Language :: C++', 'Operating System :: OS Independent', ], install_requires=['numpy>=1.10'], ### cmake portion of the setup, specific to skbuild ### setup_requires=setup_requires, cmake_args=cmake_args, py_modules=[] ) TASMANIAN-8.1/InterfacePython/Tasmanian.py000066400000000000000000000074421470551176200203030ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## # Python master module that imports all other modules and extras from TasmanianConfig import __version__ from TasmanianConfig import __license__ from TasmanianConfig import __author__ from TasmanianConfig import __git_commit_hash__ from TasmanianConfig import TasmanianInputError InputError = TasmanianInputError from TasmanianSG import * SparseGrid = TasmanianSparseGrid import TasmanianDREAM as DREAM import TasmanianOPT as Optimization from TasmanianAddons import * def useVerboseErrors(bVerbose): ''' Defines whether exceptions raised by Tasmanian should (by default) call printInfo() on exit. The info is useful for debugging, but extraneous during testing and when catching exceptions. Note that a caught Tasmanian exception will have a member boolean bShowOnExit which defined whether to printInfo(), this method sets the default for the boolean. ''' TasmanianConfig.enableVerboseErrors = False if __name__ == "__main__": with open(TasmanianConfig.__path_logfile__, 'r') as logfile: print("") print(logfile.read()) # this is a test for creating a simple grid grid = makeLocalPolynomialGrid(2, 1, 1, 1, "localp") TASMANIAN-8.1/InterfacePython/TasmanianAddons.py000066400000000000000000000562511470551176200214360ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from ctypes import c_int, c_double, c_char_p, c_void_p, POINTER, CFUNCTYPE, CDLL, RTLD_GLOBAL import numpy as np import sys import TasmanianConfig import TasmanianSG TasmanianInputError = TasmanianConfig.TasmanianInputError pLibCTSG = CDLL(TasmanianConfig.__path_libcaddons__, mode = RTLD_GLOBAL) type_1Dfunc = CFUNCTYPE(c_double, c_double) type_lpnmodel = CFUNCTYPE(None, c_int, POINTER(c_double), c_int, POINTER(c_double), c_int, POINTER(c_int)) type_scsmodel = CFUNCTYPE(None, c_int, c_int, POINTER(c_double), c_int, POINTER(c_double), c_int, POINTER(c_int)) type_icsmodel = CFUNCTYPE(None, c_int, c_int, POINTER(c_double), c_int, c_int, POINTER(c_double), c_int, POINTER(c_int)) pLibCTSG.tsgLoadNeededValues.argtypes = [c_int, type_lpnmodel, c_void_p, c_int, POINTER(c_int)] pLibCTSG.tsgConstructSurrogateNoIGSurplus.argtypes = [type_scsmodel, c_int, c_int, c_int, c_void_p, c_double, c_char_p, c_int, POINTER(c_int), c_char_p, POINTER(c_int)] pLibCTSG.tsgConstructSurrogateNoIGAniso.argtypes = [type_scsmodel, c_int, c_int, c_int, c_void_p, c_char_p, c_int, POINTER(c_int), c_char_p, POINTER(c_int)] pLibCTSG.tsgConstructSurrogateNoIGAnisoFixed.argtypes = [type_scsmodel, c_int, c_int, c_int, c_void_p, c_char_p, POINTER(c_int), POINTER(c_int), c_char_p, POINTER(c_int)] pLibCTSG.tsgConstructSurrogateWiIGSurplus.argtypes = [type_icsmodel, c_int, c_int, c_int, c_void_p, c_double, c_char_p, c_int, POINTER(c_int), c_char_p, POINTER(c_int)] pLibCTSG.tsgConstructSurrogateWiIGAniso.argtypes = [type_icsmodel, c_int, c_int, c_int, c_void_p, c_char_p, c_int, POINTER(c_int), c_char_p, POINTER(c_int)] pLibCTSG.tsgConstructSurrogateWiIGAnisoFixed.argtypes = [type_icsmodel, c_int, c_int, c_int, c_void_p, c_char_p, POINTER(c_int), POINTER(c_int), c_char_p, POINTER(c_int)] pLibCTSG.tsgLoadUnstructuredDataL2.argtypes = [POINTER(c_double), c_int, POINTER(c_double), c_double, c_void_p] pLibCTSG.tsgCreateExoticQuadratureFromGrid.argtypes = [c_void_p, c_int, c_double, c_void_p, c_char_p, c_int] pLibCTSG.tsgCreateExoticQuadratureFromFunction.argtypes = [c_void_p, c_int, c_double, type_1Dfunc, c_int, c_char_p, c_int] def tsgLnpModelWrapper(oUserModel, iSizeX, pX, iSizeY, pY, iThreadID, pErrInfo): ''' DO NOT CALL DIRECTLY This is callback from C++, see TasGrid::loadNeededValues() Creates an interface between a user callable object and the Tasmanian callback from C++. The callback passes in two raw-arrays with given sizes (that correspond to grid inputs and outputs) and the id of the running thread. The raw-array is wrapped in a numpy array structure and given to the user, the result is written to the output array. oUserModel: is callable object, e.g., function or lambda iSizeX: number of entries in x, equal to getNumDimensions() pX: raw-array corresponding to the model inputs iSizeY: number of entries in y, equal to getNumOutputs() pY: raw-array corresponding to the model outputs iThreadID: the id of the running thread ''' pErrInfo[0] = 1 aX = np.ctypeslib.as_array(pX, (iSizeX,)) aY = np.ctypeslib.as_array(pY, (iSizeY,)) aResult = oUserModel(aX, iThreadID) if aResult.shape != (iSizeY,): if TasmanianConfig.enableVerboseErrors: print("ERROR: incorrect model output dimensions, should be (iNumOutputs,)") return aY[0:iSizeY] = aResult[0:iSizeY] pErrInfo[0] = 0 def loadNeededValues(callableModel, grid, iNumThreads = 1): ''' Wrapper to TasGrid::loadNeededValues(), non-overwrite version. If the grid has needed points, the callableModel will be called for each grid point (i.e., model input) and the resulting values will be loaded in the grid. callableModel: is callable object, e.g., function or lambda The object must accept two inputs and give one output: aY = callableModel(aX, iThreadID) aX: is a one dimensional numpy.ndarray with size equal to the number of model inputs iThreadID: is the ID of the thread executing the model, always between 0 and iNumThreads -1 Two simultaneous calls to callableModel() will always have different ids. Return: aY must be a one dimensional numpy.ndarray with size equal to the number of model outputs Note: if iNumThreads > 1, then callableModel() must be thread-safe. grid: must be an instance of Tasmanian.SparseGrid() model values will be loaded in the grid iNumThreads: integer, if greater than 1 the model will be called in parallel from multiple threads. See TasGrid::loadNeededValues(). ''' iOverwrite = 0 # do not overwrite pErrorCode = (c_int * 1)() pLibCTSG.tsgLoadNeededValues(iOverwrite, type_lpnmodel(lambda nx, x, ny, y, tid, err : tsgLnpModelWrapper(callableModel, nx, x, ny, y, tid, err)), grid.pGrid, iNumThreads, pErrorCode) if pErrorCode[0] != 0: raise TasmanianInputError("loadNeededValues", "An error occurred during the call to Tasmanian.") def loadNeededPoints(callableModel, grid, iNumThreads = 1): ''' Alias to loadNeededValues() ''' loadNeededValues(callableModel, grid, iNumThreads) def reloadLoadedValues(callableModel, grid, iNumThreads = 1): ''' Wrapper to TasGrid::loadNeededPoints(), overwrite version. Clears any pending refinement (i.e., needed points) and overwrites the model values associated with the existing loaded points. The inputs are identical to Tasmanian.loadNeededPoints(). ''' iOverwrite = 1 # do overwrite pErrorCode = (c_int * 1)() pLibCTSG.tsgLoadNeededValues(iOverwrite, type_lpnmodel(lambda nx, x, ny, y, tid, err : tsgLnpModelWrapper(callableModel, nx, x, ny, y, tid, err)), grid.pGrid, iNumThreads, pErrorCode) if pErrorCode[0] != 0: raise TasmanianInputError("reloadLoadedPoints()", "An error occurred during the call to Tasmanian.") def reloadLoadedPoints(callableModel, grid, iNumThreads = 1): ''' Alias to reloadLoadedValues() ''' reloadLoadedValues(callableModel, grid, iNumThreads) ############################################################################### ################### Construct Surrogate ####################################### ############################################################################### def tsgScsModelWrapper(oUserModel, iNumSamples, iNumDims, pX, iNumOuts, pY, iThreadID, pErrInfo): ''' DO NOT CALL DIRECTLY This is callback from C++, see TasGrid::constructSurrogate() Handles the case of batch models: oUserModel: user defined model that takes a two dimensional array of inputs and returns a two dimensional array of outputs, and a thread ID iNumSamples: number of samples in the batch iNumDims: number of model inputs per sample iNumOuts: number of model outputs per sample pX and pY are 2D arrays of c_doubles with size iNumSamples times iNumDims and iNumOuts respectively iThreadID: the id of the running thread ''' pErrInfo[0] = 1 aX = np.ctypeslib.as_array(pX, (iNumSamples,iNumDims)) aY = np.ctypeslib.as_array(pY, (iNumSamples,iNumOuts)) aResult = oUserModel(aX, iThreadID) if aResult.shape != (iNumSamples, iNumOuts): if TasmanianConfig.enableVerboseErrors: print("ERROR: incorrect model output dimensions, should be (iNumSamples, iNumOutputs)") return aY[0:iNumSamples, 0:iNumOuts] = aResult[0:iNumSamples, 0:iNumOuts] pErrInfo[0] = 0 def tsgIcsModelWrapper(oUserModel, iNumSamples, iNumDims, pX, iHasGuess, iNumOuts, pY, iThreadID, pErrInfo): ''' DO NOT CALL DIRECTLY This is callback from C++, see TasGrid::constructSurrogate() See tsgScsModelWrapper(), the only difference is that the user model oUserModel() takes two arrays, one with the inputs and one with the initial guess. The initial guess could be empty. iHasGuess is a boolean that determines whether an initial guess has been loaded in pY. ''' pErrInfo[0] = 1 aX = np.ctypeslib.as_array(pX, (iNumSamples,iNumDims)) aY = np.ctypeslib.as_array(pY, (iNumSamples,iNumOuts)) if (iHasGuess == 0): # no guess aResult = oUserModel(aX, np.empty([0,0], np.float64), iThreadID) else: aResult = oUserModel(aX, aY, iThreadID) if aResult.shape != (iNumSamples, iNumOuts): if TasmanianConfig.enableVerboseErrors: print("ERROR: incorrect model output dimensions, should be (iNumSamples, iNumOutputs)") return aY[0:iNumSamples, 0:iNumOuts] = aResult[0:iNumSamples, 0:iNumOuts] pErrInfo[0] = 0 def constructAnisotropicSurrogate(callableModel, iMaxPoints, iMaxParallel, iMaxSamplesPerCall, grid, sDepthType, liAnisotropicWeightsOrOutput, liLevelLimits = [], bUseInitialGuess = False, sCheckpointFilename = ""): ''' Construct a surrogate model to the callableModel using anisotropic refinement until the iMaxPoints is reached. See the documentation for TasGrid::constructSurrogate() This is wrapper around the anisotropic refinement variant. callableModel is a function (or lambda) that returns a two dimensional numpy.ndarray of outputs for the model, If bUseInitialGuess is true, the model has to take two inputs, otherwise the model uses one. The first input is a two dimensional numpy.ndarray of inputs similar to TasmanianSparseGrid.evaluateBatch(). The second input corresponds to the initial guess, the size will either match the expected output or will be empty, if no guess can be computed. iMaxPoints: is a positive integer indicating the maximum number of points that the grid will have. iMaxParallel: is a positive integer indicating the number of simultaneous calls to the user model, i.e., the number of threads. iMaxSamplesPerCall: maximum number of samples that will be given to a single call to the user model. grid: must be an instance of Tasmanian.SparseGrid() with either global, sequence or Fourier grid. sDepthType: the type used for refinement, see TasGrid::constructSurrogate() liAnisotropicWeightsOrOutput: is either an output to use to determine the model anisotropy or a list/typle/ndarray of user selected anisotropic weights. liLevelLimits: same as in all other refinement calls, the refinement will never add points below the given level in the diven direction even if the budget has not been reached yet. sCheckpointFilename: filename to use to checkpoint the algorithm so that construction can proceed from a saved point in case of a crash. ''' iNumDims = grid.getNumDimensions() pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iNumDims): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to the grid dimension") pLevelLimits = (c_int*iNumDims)() for iI in range(iNumDims): pLevelLimits[iI] = liLevelLimits[iI] if (sys.version_info.major == 3): sDepthTypeCtypes = bytes(sDepthType, encoding='utf8') if (sCheckpointFilename): sCheckpointFilename = bytes(sCheckpointFilename, encoding='utf8') else: sDepthTypeCtypes = sDepthType pCPFname = None if (sCheckpointFilename): pCPFname = c_char_p(sCheckpointFilename) pErrorCode = (c_int * 1)() if (((sys.version_info.major == 3) and isinstance(liAnisotropicWeightsOrOutput, int)) or ((sys.version_info.major == 2) and isinstance(liAnisotropicWeightsOrOutput, (int, long)))): # will call the algorithm to dynamically estimate the weights iOutput = liAnisotropicWeightsOrOutput if (bUseInitialGuess): pLibCTSG.tsgConstructSurrogateWiIGAniso( type_icsmodel(lambda nx, nd, x, f, ny, y, tid, err : tsgIcsModelWrapper(callableModel, nx, nd, x, f, ny, y, tid, err)), iMaxPoints, iMaxParallel, iMaxSamplesPerCall, grid.pGrid, c_char_p(sDepthTypeCtypes), iOutput, pLevelLimits, pCPFname, pErrorCode) else: pLibCTSG.tsgConstructSurrogateNoIGAniso( type_scsmodel(lambda nx, nd, x, ny, y, tid, err : tsgScsModelWrapper(callableModel, nx, nd, x, ny, y, tid, err)), iMaxPoints, iMaxParallel, iMaxSamplesPerCall, grid.pGrid, c_char_p(sDepthTypeCtypes), iOutput, pLevelLimits, pCPFname, pErrorCode) else: # weights are set by the user pAnisoWeights = None if (len(liAnisotropicWeightsOrOutput) > 0): if (sDepthType in TasmanianSG.lsTsgCurvedTypes): iNumWeights = 2*grid.getNumDimensions() else: iNumWeights = grid.getNumDimensions() if (len(liAnisotropicWeightsOrOutput) != iNumWeights): raise TasmanianInputError("liAnisotropicWeightsOrOutput", "ERROR: wrong number of liAnisotropicWeightsOrOutput, sType '{0:s}' needs {1:1d} weights but len(liAnisotropicWeightsOrOutput) == {2:1d}".format(sDepthType, iNumWeights, len(liAnisotropicWeightsOrOutput))) else: aAWeights = np.array([liAnisotropicWeightsOrOutput[i] for i in range(iNumWeights)], np.int32) pAnisoWeights = np.ctypeslib.as_ctypes(aAWeights) if (bUseInitialGuess): pLibCTSG.tsgConstructSurrogateWiIGAnisoFixed( type_icsmodel(lambda nx, nd, x, f, ny, y, tid, err : tsgIcsModelWrapper(callableModel, nx, nd, x, f, ny, y, tid, err)), iMaxPoints, iMaxParallel, iMaxSamplesPerCall, grid.pGrid, c_char_p(sDepthTypeCtypes), pAnisoWeights, pLevelLimits, pCPFname, pErrorCode) else: pLibCTSG.tsgConstructSurrogateNoIGAnisoFixed( type_scsmodel(lambda nx, nd, x, ny, y, tid, err : tsgScsModelWrapper(callableModel, nx, nd, x, ny, y, tid, err)), iMaxPoints, iMaxParallel, iMaxSamplesPerCall, grid.pGrid, c_char_p(sDepthTypeCtypes), pAnisoWeights, pLevelLimits, pCPFname, pErrorCode) if pErrorCode[0] != 0: raise TasmanianInputError("constructSurplusSurrogate", "An error occurred during the call to Tasmanian.") def constructSurplusSurrogate(callableModel, iMaxPoints, iMaxParallel, iMaxSamplesPerCall, grid, fTolerance, sRefinementType, iOutput = -1, liLevelLimits = [], bUseInitialGuess = False, sCheckpointFilename = ""): ''' Construct a surrogate model to the callableModel using surplus refinement until either the iMaxPoints or the tolerance are reached. See Tasmanian.constructAnisotropicSurrogate() for all matchin inputs, except the grid has to be local polynomial and the refinement proceeds until the budget is exhausted or the fTolerance is reached. The sRefinementType is the same as in the call to local surplus refinement, same with the iOutput. ''' iNumDims = grid.getNumDimensions() pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iNumDims): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to the grid dimension") pLevelLimits = (c_int*iNumDims)() for iI in range(iNumDims): pLevelLimits[iI] = liLevelLimits[iI] pCPFname = bytes(sCheckpointFilename, encoding='utf8') if sCheckpointFilename else None pErrorCode = (c_int * 1)() if (bUseInitialGuess): pLibCTSG.tsgConstructSurrogateWiIGSurplus( type_icsmodel(lambda nx, nd, x, f, ny, y, tid, err : tsgIcsModelWrapper(callableModel, nx, nd, x, f, ny, y, tid, err)), iMaxPoints, iMaxParallel, iMaxSamplesPerCall, grid.pGrid, fTolerance, bytes(sRefinementType, encoding='utf8'), iOutput, pLevelLimits, pCPFname, pErrorCode) else: pLibCTSG.tsgConstructSurrogateNoIGSurplus( type_scsmodel(lambda nx, nd, x, ny, y, tid, err : tsgScsModelWrapper(callableModel, nx, nd, x, ny, y, tid, err)), iMaxPoints, iMaxParallel, iMaxSamplesPerCall, grid.pGrid, fTolerance, bytes(sRefinementType, encoding='utf8'), iOutput, pLevelLimits, pCPFname, pErrorCode) if pErrorCode[0] != 0: raise TasmanianInputError("constructSurplusSurrogate", "An error occurred during the call to Tasmanian.") def loadUnstructuredDataL2(points, model_data, tolerance, grid): ''' Wrapper around TasGrid::loadUnstructuredDataL2(), see the C++ reference. points is 2D ndarray with shape(num_data, grid.getNumDimensions()) model_data is 2D ndarray with shape(num_data, grid.getNumOutputs()) grid is an instance of TasmanianSparseGrid ''' if len(points.shape) != 2 or points.shape[1] != grid.getNumDimensions(): raise TasmanianInputError("points", "ERROR: points must be a 2D numpy.ndarray with points.shape[1] == grid.getNumDimensions()") if len(model_data.shape) != 2 or model_data.shape[1] != grid.getNumOutputs(): raise TasmanianInputError("model_data", "ERROR: model_data must be a 2D numpy.ndarray with model_data.shape[1] == grid.getNumOutputs()") if points.shape[0] != model_data.shape[0]: raise TasmanianInputError("model_data", "ERROR: mismatch between shape[0] of points and model_data") if not hasattr(grid, "TasmanianSparseGridObject"): raise TasmanianInputError("grid", "ERROR: grid must be an instance of TasmanianSparseGrid") num_data = points.shape[0] pLibCTSG.tsgLoadUnstructuredDataL2(np.ctypeslib.as_ctypes(points.reshape((points.size,))), num_data, np.ctypeslib.as_ctypes(model_data.reshape((model_data.size,))), tolerance, grid.pGrid) def createExoticQuadratureFromGrid(level, shift, ref_grid, description, is_symmetric = False): ''' Calls TasGrid::getExoticQuadrature() from a one dimensional interpolant/surrogate of the weight function, and output a python CustomTabulated object. See the C++ reference for more information. level: positive integer representing the level of the exotic quadrature grid. shift: double where [weight_function(x) + shift] is nonegative for every x in the domain of the weight function. ref_grid: Python TasmanianSparseGrid object that represents the one dimensional surrogate/interpolant of the weight function. description: string describing the Exotic quadrature instance. is_symmetric: (optional) boolean that should be set to True if the weight function is symmetric. output: a Python CustomTabulated object. ''' if not hasattr(ref_grid, "TasmanianSparseGridObject"): raise TasmanianInputError("ref_grid", "ERROR: ref_grid must be an instance of TasmanianSparseGrid") ct = TasmanianSG.CustomTabulated() pLibCTSG.tsgCreateExoticQuadratureFromGrid(c_void_p(ct.pCustomTabulated), c_int(level), c_double(shift), c_void_p(ref_grid.pGrid), bytes(description, encoding='utf8'), c_int(is_symmetric)) return ct def createExoticQuadratureFromFunction(level, shift, weight_fn, nref, description, is_symmetric = False): ''' Calls TasGrid::getExoticQuadrature() from a function lambda representing the weight function, and output a Python CustomTabulated object. See the C++ reference for more information. level: positive integer representing the level of the exotic quadrature grid. shift: double where [weight_function(x) + shift] is nonegative for every x in the domain of the weight function. weight_fn: Python lambda function representing the weight function. nref: positive integer representing the number of points used to generate the weight function surrogate/interpolant. description: string describing the Exotic quadrature instance. is_symmetric: (optional) boolean that should be set to True if the weight function is symmetric. output: a Python CustomTabulated object. ''' ct = TasmanianSG.CustomTabulated() pLibCTSG.tsgCreateExoticQuadratureFromFunction(c_void_p(ct.pCustomTabulated), c_int(level), c_double(shift), type_1Dfunc(weight_fn), c_int(nref), bytes(description, encoding='utf8'), c_int(is_symmetric)) return ct TASMANIAN-8.1/InterfacePython/TasmanianConfig.in.py000066400000000000000000000103011470551176200220220ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## # Using a single configuration file with all paths and relevant options # The rest of the Tasmanian Python modules will not be configured by cmake __version__ = "@Tasmanian_VERSION_MAJOR@.@Tasmanian_VERSION_MINOR@" __license__ = "@Tasmanian_license@" __author__ = "Miroslav Stoyanov" __git_commit_hash__ = "@Tasmanian_git_hash@" __path_libsparsegrid__ = "@Tasmanian_libsparsegrid_path@" __path_libdream__ = "@Tasmanian_libdream_path@" __path_libcaddons__ = "@Tasmanian_libcaddons_path@" __path_logfile__ = "@Tasmanian_final_install_path@/share/Tasmanian/Tasmanian.log" enableVerboseErrors = True # the transitive library dependencies on Linux/OsX are handled by rpath, Windows needs help if "@CMAKE_SYSTEM_NAME@" == "Windows": import os os.environ['PATH'] = "@Tasmanian_libpaths@" + os.pathsep + os.environ['PATH'] class TasmanianInputError(Exception): '''Exception raised for incorrect input to Tasmanian Attributes: sVariable -- string containing the variable name with incorrect value sMessage -- message regarding the error bShowOnExit -- boolean indicates whether to call printInfo() form the destructor ''' def __init__(self, sVar, sMess): self.sVariable = sVar self.sMessage = sMess self.bShowOnExit = enableVerboseErrors def __del__(self): if self.bShowOnExit: self.printInfo() def printInfo(self): ''' prints information for the incorect function or variable ''' print("Incorrect input for: {0:s}".format(self.sVariable)) print(self.sMessage) TASMANIAN-8.1/InterfacePython/TasmanianDREAM.py000066400000000000000000000053631470551176200210540ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from TasmanianDreamLikely import * from TasmanianDreamSampler import * from TasmanianDreamState import DreamState as State TASMANIAN-8.1/InterfacePython/TasmanianDreamLikely.py000066400000000000000000000147541470551176200224320ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from ctypes import c_char_p, c_int, c_double, c_void_p, POINTER, CDLL, create_string_buffer, RTLD_GLOBAL import numpy as np import sys from TasmanianConfig import __path_libdream__ from TasmanianConfig import TasmanianInputError as InputError pLibDTSG = CDLL(__path_libdream__, mode = RTLD_GLOBAL) pLibDTSG.tsgGetNumOutputsLikelihood.restype = c_int pLibDTSG.tsgDeleteLikelihood.argtypes = [c_void_p] pLibDTSG.tsgGetNumOutputsLikelihood.argtypes = [c_void_p] pLibDTSG.tsgGetLikelihood.argtypes = [c_void_p, c_int, POINTER(c_double), c_int, POINTER(c_double)] pLibDTSG.tsgMakeLikelihoodGaussIsotropic.restype = c_void_p pLibDTSG.tsgMakeLikelihoodGaussIsotropic.argtypes = [c_int, c_double, POINTER(c_double), c_int] pLibDTSG.tsgMakeLikelihoodGaussAnisotropic.restype = c_void_p pLibDTSG.tsgMakeLikelihoodGaussAnisotropic.argtypes = [c_int, POINTER(c_double), POINTER(c_double), c_int] typeRegform = 0 typeLogform = 1 class TasmanianLikelihood(object): ''' Generic wrapper to TasDREAM::TasmanianLikelihood derived class. ''' def __init__(self): ''' The derived classes will have a member pClassPntr, init to nullptr here. ''' self.TasmanianLikelihood = True self.pClassPntr = c_void_p(None) def __del__(self): ''' Delete the grid on exit ''' if self.pClassPntr: pLibDTSG.tsgDeleteLikelihood(self.pClassPntr) def getNumOutputs(self): ''' Returns the number of outputs set in the likelihood. ''' return pLibDTSG.tsgGetNumOutputs(self.pClassPntr) def getLikelihood(self, typeForm, llfModel): ''' Returns the likelihood for the model outputs. typeForm: indicates to use the regular or log-form use DREAM.typeRegform or DREAM.typeLogform llfModel: is a two dimensional numpy.ndarray with .shape[0] > 0 .shape[1] == getNumOutputs() Returns a one dimensional ndarray with size .shape[0] ''' iNumSamples = llfModel.shape[0] iNumOutputs = llfModel.shape[1] aResult = np.empty((iNumSamples,), np.float64) pLibDTSG.tsgGetLikelihood(self.pClassPntr, typeForm, np.ctypeslib.as_ctypes(llfModel.reshape((iNumSamples*iNumOutputs,))), iNumSamples, np.ctypeslib.as_ctypes(aResult)) return aResult class LikelihoodGaussIsotropic(TasmanianLikelihood): ''' Wrapper around TasDREAM::LikelihoodGaussIsotropic ''' def __init__(self, fVariance, lfData, iNumSamples = 1): ''' Make a new likelihood with the given data. fVariance: float64 is the variance lfData: one dimensional ndarray with the data iNumSamples: number of samples used for the data ''' super(LikelihoodGaussIsotropic, self).__init__() iNumOutputs = len(lfData) self.pClassPntr = pLibDTSG.tsgMakeLikelihoodGaussIsotropic( iNumOutputs, fVariance, np.ctypeslib.as_ctypes(lfData), iNumSamples) class LikelihoodGaussAnisotropic(TasmanianLikelihood): ''' Wrapper around TasDREAM::LikelihoodGaussIsotropic ''' def __init__(self, lfVariance, lfData, iNumSamples = 1): ''' Make a new likelihood with the given data. lfVariance: one dimensional ndarray with the data variance lfData: one dimensional ndarray with the data iNumSamples: number of samples used for the data ''' super(LikelihoodGaussAnisotropic, self).__init__() if (len(lfVariance) != len(lfData)): raise InputError("lfVariance", "Mismatch in size of variance and data vectors.") iNumOutputs = len(lfData) self.pClassPntr = pLibDTSG.tsgMakeLikelihoodGaussAnisotropic( iNumOutputs, np.ctypeslib.as_ctypes(lfVariance), np.ctypeslib.as_ctypes(lfData), iNumSamples) TASMANIAN-8.1/InterfacePython/TasmanianDreamSampler.py000066400000000000000000000711121470551176200225730ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from ctypes import c_char_p, c_int, c_double, c_void_p, POINTER, CDLL, CFUNCTYPE, RTLD_GLOBAL import numpy as np import sys from TasmanianConfig import __path_libdream__ from TasmanianConfig import enableVerboseErrors from TasmanianConfig import TasmanianInputError as InputError from TasmanianSG import TasmanianSparseGrid as SparseGrid from TasmanianDreamLikely import * from TasmanianDreamState import DreamState as State type_dream_pdf = CFUNCTYPE(None, c_int, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_int)) type_dream_domain = CFUNCTYPE(c_int, c_int, POINTER(c_double)) type_dream_iupdate = CFUNCTYPE(None, c_int, POINTER(c_double), POINTER(c_int)) type_dream_dupdate = CFUNCTYPE(c_double) type_dream_random = CFUNCTYPE(c_double) pLibDTSG = CDLL(__path_libdream__, mode = RTLD_GLOBAL) pLibDTSG.tsgGenUniformSamples.argtypes = [c_int, c_int, POINTER(c_double), POINTER(c_double), c_char_p, c_int, type_dream_random, POINTER(c_double)] pLibDTSG.tsgGenGaussianSamples.argtypes = [c_int, c_int, POINTER(c_double), POINTER(c_double), c_char_p, c_int, type_dream_random, POINTER(c_double)] pLibDTSG.tsgDreamSample.argtypes = [c_int, c_int, c_int, type_dream_pdf, c_void_p, c_void_p, POINTER(c_double), POINTER(c_double), type_dream_domain, c_char_p, c_double, type_dream_iupdate, c_int, type_dream_dupdate, c_char_p, c_int, type_dream_random, POINTER(c_int)] def pdfWrapper(callableProbability, iNumSamples, iNumDims, pX, pY, pErrInfo): ''' Internal use only. Wraps around a user-provided callable method callableProbability to facilitate callback from the C/C++ code. The wrapper corresponds to a single output pdf/likelihood method. iNumSamples is the number of samples to process for this call. iNumDims is the number of dimensions of each sample vector pX is a POINTER(double) with size iNumSamples * iNumDims pY is a POINTER(double) with size iNumSamples ''' pErrInfo[0] = 1 aX = np.ctypeslib.as_array(pX, (iNumSamples, iNumDims)) aY = np.ctypeslib.as_array(pY, (iNumSamples,)) aResult = callableProbability(aX) if aResult.shape != (iNumSamples,) and enableVerboseErrors: print("ERROR: incorrect output from the probability distribution, should be (iNumSamples,)") return aY[0:iNumSamples] = aResult[0:iNumSamples] pErrInfo[0] = 0 def domainWrapper(callableDomain, iNumDims, pX): ''' Internal use only. Wraps around a user-provided callable method callableDomain to facilitate callback from the C/C++ code. The wrapper corresponds to the test of a single point. iNumDims is the dimensions of the point pX is a POINTER(double) with size iNumDims returns 1 if callableDomain() returns true and 0 otherwise. ''' aX = np.ctypeslib.as_array(pX, (iNumDims,)) if callableDomain(aX): return 1; else: return 0 def iupdateWrapper(callableIUpdate, iNumDims, pX, pErrInfo): ''' Internal use only. Wraps around a user-provided callable method callableIUpdate to facilitate callback from the C/C++ code. The wrapper corresponds to the independent update of a single point. iNumDims is the dimensions of the point pX is a POINTER(double) with size iNumDims pX will be overwritten with pX + update ''' pErrInfo[0] = 1 aX = np.ctypeslib.as_array(pX, (iNumDims,)) aResult = callableIUpdate() if aResult.shape != (iNumDims,) and enableVerboseErrors: print("ERROR: incorrect output from the independent update, should be (iNumDimensions,)") return aX[0:iNumDims] = aResult[0:iNumDims] pErrInfo[0] = 0 class Domain(object): ''' Domain objects specify the domain of sampling and is used to test each candidate sample. The objects roughly correspond to the inside() parameter given to TasDREAM::SampleDREAM() but with extra flexibility to reduce the cost of C++ to Python callbacks. The domain can be specified in one of the following ways: 1) Domain(grid) The grid is an instance of Tasmanian.SparseGrid() and the domain will match the domain of the sparse grid. The grid domain is usually a hypercube with lower and upper limit, but in some cases, e.g., using gauss-hermite and gauss-laguerre rules, the domain can be unbounded in some directions. 2) Domain("hypercube", aLower, aUpper) The domain will be set to a hypercube, similar to TasDREAM::hypercube(). The aLower and aUpper must be one dimensional numpy.ndarrays with size equal to the dimensions of the domain and the corresponding values must specify the lower and upper limit in each direction. 3) Domain("unbounded") Samples will be accepted and rejected only based on the probability density, i.e., the sampling domain includes all real valued vectors. 4) Domain("custom", inside) The inside parameter must be a callable object that accepts an single numpy.ndarray with size equal to the number of dimensions, and must return True or False depending on whether the vector is inside the domain. ''' def __init__(self, sType, *args): ''' Constructor that translates the input arguments into inputs to the internal Tasmanian API. See help(Tasmanian.DREAM.Domain) ''' self.TasmanianDreamDomain = True if hasattr(sType, "TasmanianSparseGridObject"): self.pGrid = sType.pGrid self.pLower = None self.pUpper = None self.pCallable = type_dream_domain(lambda : 1) elif sType == "hypercube": self.pGrid = None self.pLower = np.ctypeslib.as_ctypes(args[0]) self.pUpper = np.ctypeslib.as_ctypes(args[1]) self.pCallable = type_dream_domain(lambda : 1) elif sType == "unbounded": self.pGrid = None self.pLower = None self.pUpper = None self.pCallable = type_dream_domain(lambda n, x : domainWrapper(lambda x: True, n, x)) elif sType == "custom": self.pGrid = None self.pLower = None self.pUpper = None self.pCallable = type_dream_domain(lambda n, x : domainWrapper(args[0], n, x)) else: raise InputError("Domain", "DREAM.Domain() was given an unknown domain type") class IndependentUpdate(object): ''' Each step of the DREAM procedure uses two updates to generate new proposed vectors for each chain. The independent update is a zero-mean random vector pulled from a distribution that does not depend on the other DREAM chains. Thus is the Python equivalent to the independent_update() parameter to TasDREAM::SampleDREAM(). The independent update can be specified in one of the following ways: 1) IndependentUpdate(sType, fMagnitude) The sType is a string and fMagnitude is a float64 corresponding to the dist and magnitude of the TasDREAM::SampleDREAM() overload. The sType must be either "gaussian" or "uniform". Note that the magnitude can be zero. 2) IndependentUpdate(iupdate) The iupdate must be a callable object that accepts a numpy.ndarray with length equal to the sampling dimension and returns same vector but perturbed with the update, e.g., lambda x : x + update(). ''' def __init__(self, sType, callableOrMagnitude = 0.0): ''' Constructor that translates the input arguments into inputs to the internal Tasmanian API. See help(Tasmanian.DREAM.IndependentUpdate) ''' self.TasmanianDreamIndependentUpdate = True if not ((sys.version_info.major == 3 and isinstance(sType, str)) or (sys.version_info.major == 2 and isinstance(sType, basestring))): if not callable(sType): raise InputError("sType", "DREAM.IndependentUpdate() the sType must be either a string or a callable object") self.sType = "null" self.fMagnitude = 0.0 self.pCallable = type_dream_iupdate(lambda n, x, err : iupdateWrapper(sType, n, x, err)) else: self.sType = sType self.fMagnitude = callableOrMagnitude self.pCallable = type_dream_iupdate(lambda : 1) if (sys.version_info.major == 3): self.sType = bytes(self.sType, encoding='utf8') class DifferentialUpdate(object): ''' Each step of the DREAM procedure uses two updates to generate new proposed vectors for each chain. The differential update is defined as a scale multiplied by the difference between two of the DREAM chains. This class sets the scale, i.e., the magnitude of the differential update. Thus is the Python equivalent to the differential_update() parameter to TasDREAM::SampleDREAM(). The differential update can be specified in one of the following ways: 1) DifferentialUpdate(iMagnitude) The iMagnitude is an integer that defines the percent scale of the differential update, i.e., the update is float(iMagnitude) / 100.0 This is equivalent to using TasDREAM::const_percent in the C++ call to TasDREAM::SampleDREAM(). 2) DifferentialUpdate(dupdate) The dupdate must be a callable object that accepts no inputs and returns a float64 indicating the magnitude. Note: by symmetry, positive and negative scales with the same magnitude are statistically equivalent. ''' def __init__(self, callableOrMagnitude): ''' Constructor that translates the input arguments into inputs to the internal Tasmanian API. See help(Tasmanian.DREAM.DifferentialUpdate) ''' self.TasmanianDreamDifferentialUpdate = True if (((sys.version_info.major == 3) and isinstance(callableOrMagnitude, int)) or ((sys.version_info.major == 2) and isinstance(callableOrMagnitude, (int, long)))): self.iPercent = callableOrMagnitude self.pCallable = type_dream_dupdate(lambda : 1) else: if not callable(callableOrMagnitude): raise InputError("callableOrMagnitude", "DREAM.DifferentialUpdate() the callableOrMagnitude must be either an integer or a callable object") self.iPercent = -1 self.pCallable = type_dream_dupdate(callableOrMagnitude) class RandomGenerator(object): ''' A class that helps specify the random number generator to be used on the C++ side of the call to TasDREAM::SampleDREAM(). The random number engine can be defined in one of several ways: 1) RandomGenerator("default") or just RandomGenerator() The C++ code will use the rand() command with seed initialized from the system time. 2) RandomGenerator("minstd_rand") The rand() command in C++ is implementation dependent, i.e., the random number may be different between compilers even if the same seed is used. The std::minstd_rand generator is defined in the standard and the output is implementation independent, which makes it a good option for testing and debugging (probably not very good for actual applications). The random seed used here will still be taken from the system time. 3) RandomGenerator("minstd_rand", iSeed) In addition to the standard std::minstd_rand engine this also specifies the seed. 4) RandomGenerator(callableRNG = random01) The random01 parameter must be a callable object that returns random numbers distributed uniformly in (0, 1), e.g., from random import uniform RandomGenerator(callableRNG = lambda : uniform(0.0, 1.0)) ''' def __init__(self, sType = "default", iSeed = -1, callableRNG = lambda : 1): ''' Constructor that translates the input arguments into inputs to the internal Tasmanian API. See help(Tasmanian.DREAM.RandomGenerator) ''' if sType not in ["default", "minstd_rand"]: raise InputError("sType", "DREAM.RandomGenerator() the sType is invalid") if not callable(callableRNG): raise InputError("callableRNG", "DREAM.RandomGenerator() the callableRNG must be a callable object") self.TasmanianDreamRandomGenerator = True self.sType = sType if (sys.version_info.major == 3): self.sType = bytes(self.sType, encoding='utf8') self.iSeed = iSeed self.pCallable = type_dream_random(callableRNG) typePriorCallable = 0 # internal API, the values are synchronized with the C/C++ code typePriorUniform = 1 class Posterior(object): ''' A class that helps combine the components of a Bayesian posterior into a single callable object. Strictly speaking, this is a factory class that generates probability distribution callable objects used in DREAM.Sample(). The intended use of the class is embedded as in the C++ function TasDREAM::posterior(). The probability distribution takes a two dimensional numpy.ndarray object with shape (num_samples, num_dimensions) and returns a one dimensional numpy.ndarray with length (num_samples,). Each entry of the result corresponds to the (unscaled) probability density at the corresponding vector. The usage of this class is: DREAM.Sample(..., Posterior(model, likelihood, prior), ...) or if log-form sampling is to be used: DREAM.Sample(..., Posterior(model, likelihood, prior, typeForm), ...) Combining the three components gives us: result = likelihood(typeForm, model(x)) * prior(x) of if using typeLogform: result = likelihood(typeForm, model(x)) + prior(x) The model, likelihood, and prior, can be callable objects so that model: input.shape = (num_samples, num_dimensions) output.shape = (num_samples, num_outputs) likelihood: input.shape = (num_samples, num_outputs) output.shape = (num_samples,) prior: input.shape = (num_samples, num_dimensions) output.shape = (num_samples,) In addition: model: can be an instance of Tasmanian.SparseGrid() likelihood: can be an instance of DREAM.LikelihoodGaussIsotropic() of LikelihoodGaussAnisotropic(). prior: can be the string "uniform" The typeForm must be either typeRegform (default) or typeLogform and must be synchronized with the form used in DREAM.Sample(). The likelihood need only implement the form used in DREAM.Sample(). The form here indicates whether to add or multiply by the log of the values of the prior. ''' def __init__(self, model, likelihood, prior, typeForm = typeRegform): ''' Constructor that translates the input arguments into inputs to the internal Tasmanian API. See help(Tasmanian.DREAM.Posterior) ''' self.TasmanianPosterior = True self.typeForm = typeForm if self.typeForm not in [typeRegform, typeLogform]: raise InputError("typeForm", "unknown sampling form, must use typeRegform or typeLogform") self.model = model if hasattr(self.model, "TasmanianSparseGridObject"): self.bUseSparsegrid = True elif callable(self.model): self.bUseSparsegrid = False else: raise InputError("model", "model should be either an instance of Tasmanian.SparseGrid() or a callable object.") self.likelihood = likelihood if hasattr(self.likelihood, "TasmanianLikelihood"): self.bUseTasLikely = True elif callable(self.likelihood): self.bUseTasLikely = False else: raise InputError("likelihood", "likelihood should be either derived from TasmanianLikelihood() or a callable object.") if prior == "uniform": self.typePrior = typePriorUniform elif callable(prior): self.typePrior = typePriorCallable self.prior = prior else: raise InputError("prior", "prior should be either 'uniform' or a callable object.") def doModel(self, aX): ''' Internal API, applies the model part of the posterior. ''' if self.bUseSparsegrid: return self.model.evaluateBatch(aX) else: return self.model(aX) def doLikelihood(self, aModelValues): ''' Internal API, applies the likelihood part of the posterior. ''' if self.bUseTasLikely: return self.likelihood.getLikelihood(self.typeForm, aModelValues) else: return self.likelihood(self.typeForm, aModelValues) def doPrior(self, aLikely, aX): ''' Internal API, computes the prior part of the posterior. ''' if self.typePrior == typePriorUniform: aResult = aLikely else: # reg-form multiplies, log-form adds if self.typeForm == typeRegform: aResult = aLikely * self.prior(aX) else: aResult = aLikely + self.prior(aX) return aResult def distribution(self): ''' Internal API, combines the input objects into a single lambda. ''' return lambda x : self.doPrior(self.doLikelihood(self.doModel(x)), x).reshape((x.shape[0],)) def PosteriorEmbeddedLikelihood(model, prior, typeForm = typeRegform): ''' Shortcut to Tasmanian.DREAM.Posterior() when the model and the likelihood are combined into a single object (callable or sparse grid). The prior and typeForm are the same. ''' return Posterior(model, lambda t, x : x, prior, typeForm) def genUniformSamples(lfLower, lfUpper, iNumSamples, random01 = RandomGenerator(sType = "default")): ''' Wrapper around TasDREAM::genUniformSamples() Using the one dimensional numpy.ndarrays lfLower and lfUpper, which describe the upper and lower bounds of a hypercube, generate iNumSamples from a uniform distribution using the random01 engine. The lengths of lfLower and lfUpper must match. Returns a two dimensional numpy.ndarray of shape = (iNumSamples, len(lfLower)), ''' if len(lfLower) != len(lfUpper): raise InputError("lfUpper", "The length of lfLower and lfUpper do not match.") aLower = np.array(lfLower) aUpper = np.array(lfUpper) iNumDims = len(lfLower) aResult = np.empty((iNumDims * iNumSamples,), np.float64) pLibDTSG.tsgGenUniformSamples(iNumDims, iNumSamples, np.ctypeslib.as_ctypes(aLower), np.ctypeslib.as_ctypes(aUpper), c_char_p(random01.sType), random01.iSeed, random01.pCallable, np.ctypeslib.as_ctypes(aResult)) return aResult.reshape((iNumSamples, iNumDims)) def genGaussianSamples(lfMean, lfDeviation, iNumSamples, random01 = RandomGenerator(sType = "default")): ''' Wrapper around TasDREAM::tsgGenGaussianSamples() Using the one dimensional numpy.ndarrays lfMean and lfVariance, which describe the mean and standard deviation of a Gaussian distribution, generate iNumSamples from a normal (Gaussian) distribution using the random01 engine. The lengths of lfMean and lfDeviation must match. Returns a two dimensional numpy.ndarray of shape = (iNumSamples, len(lfLower)), ''' if len(lfMean) != len(lfDeviation): raise InputError("lfDeviation", "The length of lfMean and lfDeviation do not match.") aMean = np.array(lfMean) aDeviation = np.array(lfDeviation) iNumDims = len(lfMean) aResult = np.empty((iNumDims * iNumSamples,), np.float64) pLibDTSG.tsgGenGaussianSamples(iNumDims, iNumSamples, np.ctypeslib.as_ctypes(aMean), np.ctypeslib.as_ctypes(aDeviation), c_char_p(random01.sType), random01.iSeed, random01.pCallable, np.ctypeslib.as_ctypes(aResult)) return aResult.reshape((iNumSamples, iNumDims)) def Sample(iNumBurnup, iNumCollect, probability_distibution, domain_description, dream_state, independent_update = IndependentUpdate("none"), differential_update = DifferentialUpdate(100), random01 = RandomGenerator(sType = "default"), typeForm = typeRegform): ''' Wrapper to TasDREAM::SampleDREAM(). The Markov Chain Monte Carlo algorithms generate chains of samples with distribution that converges to the target probability density. The current state of the chains (i.e., the last vector) is updated by first generating a set of proposals and then accepting/rejecting randomly but with the constraint that the only accepted vectors belong to the specified domain. The proposals are constructed from two components, the independent component that is iid random with zero mean and the differential component that is takes from the scaled difference between the state of two randomly selected chains. iNumBurnup: is a non-negative integer that indicates the number of iterations to discard, i.e., samples that have no statistical significance because the chain state has not converged to the target probability distribution. iNumCollect: is a non-negative integer that indicates the number of iterations to store in the state history. probability_distibution: is either an instance of DREAM.Posterior() or a callable object that accepts a two dimensional numpy.ndarray and then returns a one dimensional numpy.ndarray. See help(Tasmanian.DREAM.Posterior) Can also use a lambda to capture a Tasmanian sparse grid, i.e., lambda x : grid.evaluateBatch(x).reshape((x.shape[0],)) domain_description: is an instance of DREAM.Domain() See help(Tasmanian.DREAM.Domain) dream_state: is an instance of DREAM.State() with number of dimensions that match the dimensions used by the probability_distibution. See help(Tasmanian.DREAM.State) On input the state chains have to be initialized, on output the history will be populated with the iNumCollect samples. (if the history is not empty, the new samples will be appended) independent_update: is an instance of DREAM.IndependentUpdate() See help(Tasmanian.DREAM.IndependentUpdate) differential_update: is an instance of DREAM.DifferentialUpdate() See help(Tasmanian.DREAM.DifferentialUpdate) random01: is an instance of DREAM.RandomGenerator() See help(Tasmanian.DREAM.RandomGenerator) typeForm: is either DREAM.typeRegform or DREAM.typeLogform The form modifies the accept/reject criteria based on whether the probability_distibution returns the actual distribution of interest or the logarithm of that (which is sometimes more stable and/or easier to approximate with a sparse grid). Note: the typeForm must match the return of the probability_distibution. ''' if not hasattr(domain_description, "TasmanianDreamDomain"): raise InputError("domain_description", "domain_description must be an instance of DREAM.Domain()") if not hasattr(dream_state, "TasmanainDreamState"): raise InputError("dream_state", "dream_state must be an instance of DREAM.State()") if not hasattr(independent_update, "TasmanianDreamIndependentUpdate"): raise InputError("independent_update", "independent_update must be an instance of DREAM.IndependentUpdate()") if not hasattr(differential_update, "TasmanianDreamDifferentialUpdate"): raise InputError("differential_update", "differential_update must be an instance of DREAM.DifferentialUpdate()") if not hasattr(random01, "TasmanianDreamRandomGenerator"): raise InputError("random01", "random01 must be an instance of DREAM.RandomGenerator()") if typeForm not in [typeRegform, typeLogform]: raise InputError("typeForm", "unknown sampling form, must use typeRegform or typeLogform") pErrorCode = (c_int * 1)() if hasattr(probability_distibution, "TasmanianPosterior"): pLibDTSG.tsgDreamSample(typeForm, c_int(iNumBurnup), c_int(iNumCollect), type_dream_pdf(lambda m, n, x, y, err : pdfWrapper(probability_distibution.distribution(), m, n, x, y, err)), dream_state.pStatePntr, domain_description.pGrid, domain_description.pLower, domain_description.pUpper, domain_description.pCallable, c_char_p(independent_update.sType), independent_update.fMagnitude, independent_update.pCallable, differential_update.iPercent, differential_update.pCallable, c_char_p(random01.sType), random01.iSeed, random01.pCallable, pErrorCode) elif callable(probability_distibution): pLibDTSG.tsgDreamSample(typeForm, c_int(iNumBurnup), c_int(iNumCollect), type_dream_pdf(lambda m, n, x, y, err : pdfWrapper(probability_distibution, m, n, x, y, err)), dream_state.pStatePntr, domain_description.pGrid, domain_description.pLower, domain_description.pUpper, domain_description.pCallable, c_char_p(independent_update.sType), independent_update.fMagnitude, independent_update.pCallable, differential_update.iPercent, differential_update.pCallable, c_char_p(random01.sType), random01.iSeed, random01.pCallable, pErrorCode) else: raise InputError("probability_distibution", "probability_distibution must be a callable object that takes a 2D numpy.ndarray and returns a 1D ndarray") if pErrorCode[0] != 0: raise InputError("Sample", "An error occurred during the call to Tasmanian.") TASMANIAN-8.1/InterfacePython/TasmanianDreamState.py000066400000000000000000000176321470551176200222570ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from ctypes import c_char_p, c_int, c_double, c_void_p, POINTER, CDLL, create_string_buffer, RTLD_GLOBAL import numpy as np import sys from TasmanianConfig import __path_libdream__ from TasmanianConfig import TasmanianInputError as InputError from TasmanianSG import TasmanianSparseGrid as SparseGrid pLibDTSG = CDLL(__path_libdream__, mode = RTLD_GLOBAL) pLibDTSG.tsgMakeDreamState.restype = c_void_p pLibDTSG.tsgMakeDreamState.argtypes = [c_int, c_int] pLibDTSG.tsgDeleteDreamState.argtypes = [c_void_p] pLibDTSG.tsgDreamStateGetDims.restype = c_int pLibDTSG.tsgDreamStateGetDims.argtypes = [c_void_p] pLibDTSG.tsgDreamStateGetChains.restype = c_int pLibDTSG.tsgDreamStateGetChains.argtypes = [c_void_p] pLibDTSG.tsgDreamStateGetNumHistory.restype = c_int pLibDTSG.tsgDreamStateGetNumHistory.argtypes = [c_void_p] pLibDTSG.tsgDreamStateSet.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgDreamStateGetHistory.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgDreamStateGetHistoryPDF.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgDreamStateGetMeanVar.argtypes = [c_void_p, POINTER(c_double), POINTER(c_double)] pLibDTSG.tsgDreamStateGetMode.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgDreamStateGetRate.restype = c_double pLibDTSG.tsgDreamStateGetRate.argtypes = [c_void_p] class DreamState: ''' Wrapper to class TasDREAM::TasmanianDREAM ''' def __init__(self, iNumChains, GridOrIntDimensions): ''' Constructs a new state with given number of chains and dimensions. The dimensions can be given as an integer or inferred from a Tasmanian.SparseGrid object. iNumChains: positive integer indicating the number of chains. GridOrIntDimensions: either a positive integer or a non-empty Tasmanian.SparseGrid object that gives the dimensions ''' self.TasmanainDreamState = True if (isinstance(GridOrIntDimensions, SparseGrid)): self.pStatePntr = pLibDTSG.tsgMakeDreamState(iNumChains, GridOrIntDimensions.getNumDimensions()) else: self.pStatePntr = pLibDTSG.tsgMakeDreamState(iNumChains, GridOrIntDimensions) def __del__(self): ''' Deletes an instance of the DREAM state. ''' pLibDTSG.tsgDeleteDreamState(self.pStatePntr) def getNumDimensions(self): ''' Return the number of dimensions. ''' return pLibDTSG.tsgDreamStateGetDims(self.pStatePntr) def getNumChains(self): ''' Return the number of chains. ''' return pLibDTSG.tsgDreamStateGetChains(self.pStatePntr) def getNumHistory(self): ''' Return the number of samples saved in the history. ''' return pLibDTSG.tsgDreamStateGetNumHistory(self.pStatePntr) def setState(self, llfNewState): ''' Set a new state for the DREAM chains. llfNewState: is a two dimensional numpy.ndarray with .shape[0] = .getNumChains() .shape[1] = .getNumDimensions() ''' iNumChains = self.getNumChains() iNumDims = self.getNumDimensions() if (llfNewState.shape[0] != iNumChains): raise InputError("llfNewState", "llfNewState.shape[0] should match the number of chains") if (llfNewState.shape[1] != iNumDims): raise InputError("llfNewState", "llfNewState.shape[1] should match the number of dimensions") pLibDTSG.tsgDreamStateSet(self.pStatePntr, np.ctypeslib.as_ctypes(llfNewState.reshape((iNumChains * iNumDims,)))) def getHistory(self): ''' Returns the saved history in a two dimensional numpy.ndarray ''' iNumDims = self.getNumDimensions() iNumHistory = self.getNumHistory() aResult = np.empty((iNumDims * iNumHistory,), np.float64) pLibDTSG.tsgDreamStateGetHistory(self.pStatePntr, np.ctypeslib.as_ctypes(aResult)) return aResult.reshape((iNumHistory, iNumDims)) def getHistoryPDF(self): ''' Returns the saved pdf in a one dimensional numpy.ndarray ''' iNumHistory = self.getNumHistory() aResult = np.empty((NumHistory,), np.float64) pLibDTSG.tsgDreamStateGetHistoryPDF(self.pStatePntr, np.ctypeslib.as_ctypes(aResult)) return aResult def getHistoryMeanVariance(self): ''' Returns two one dimensional numpy.ndarrays corresponding to the mean and variance of the history. ''' iNumDims = self.getNumDimensions() aMean = np.empty((iNumDims,)) aVar = np.empty((iNumDims,)) pLibDTSG.tsgDreamStateGetMeanVar(self.pStatePntr, np.ctypeslib.as_ctypes(aMean), np.ctypeslib.as_ctypes(aVar)) return aMean, aVar def getApproximateMode(self): ''' Returns the approximate mode, i.e., the sample with highest probability density. ''' iNumDims = self.getNumDimensions() aMode = np.empty((iNumDims,)) pLibDTSG.tsgDreamStateGetMode(self.pStatePntr, np.ctypeslib.as_ctypes(aMode)) return aMode def getAcceptanceRate(self): ''' Return the acceptance rate accumulated with the history. ''' return pLibDTSG.tsgDreamStateGetRate(self.pStatePntr) TASMANIAN-8.1/InterfacePython/TasmanianGradientDescent.py000066400000000000000000000417011470551176200232630ustar00rootroot00000000000000# Copyright (c) 2022, Miroslav Stoyanov & Weiwei Kong # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND # IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF # THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL # ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES # RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING # FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. from ctypes import c_char_p, c_int, c_double, c_void_p, POINTER, CDLL, cast, CFUNCTYPE, Structure, RTLD_GLOBAL from numpy.ctypeslib import as_ctypes import numpy as np import sys from TasmanianConfig import __path_libdream__ from TasmanianConfig import TasmanianInputError as InputError type_optim_obj_fn_single = CFUNCTYPE(c_double, c_int, POINTER(c_double), POINTER(c_int)) type_optim_grad_fn_single = CFUNCTYPE(None, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_int)) type_optim_proj_fn_single = CFUNCTYPE(None, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_int)) # OptimizationStatus class (mirrors the C++ struct). class optimization_status(Structure): pass optimization_status._fields_ = [("performed_iterations", c_int), ("residual", c_double)] def clean_status(input_status): return dict((field, getattr(input_status, field)) for field, _ in input_status._fields_) pLibDTSG = CDLL(__path_libdream__, mode = RTLD_GLOBAL) pLibDTSG.tsgGradientDescentState_Construct.restype = c_void_p pLibDTSG.tsgGradientDescentState_Construct.argtypes = [c_int, POINTER(c_double), c_double] pLibDTSG.tsgGradientDescentState_Destruct.argtypes = [c_void_p] pLibDTSG.tsgGradientDescentState_GetNumDimensions.restype = c_int pLibDTSG.tsgGradientDescentState_GetNumDimensions.argtypes = [c_void_p] pLibDTSG.tsgGradientDescentState_GetAdaptiveStepsize.restype = c_double pLibDTSG.tsgGradientDescentState_GetAdaptiveStepsize.argtypes = [c_void_p] pLibDTSG.tsgGradientDescentState_GetX.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgGradientDescentState_SetAdaptiveStepsize.argtypes = [c_void_p, c_double] pLibDTSG.tsgGradientDescentState_SetX.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgGradientDescent_AdaptProj.argtypes = [type_optim_obj_fn_single, type_optim_grad_fn_single, type_optim_proj_fn_single, c_double, c_double, c_int, c_double, c_void_p, POINTER(c_int)] pLibDTSG.tsgGradientDescent_AdaptProj.restype = optimization_status pLibDTSG.tsgGradientDescent_Adapt.argtypes = [type_optim_obj_fn_single, type_optim_grad_fn_single, c_double, c_double, c_int, c_double, c_void_p, POINTER(c_int)] pLibDTSG.tsgGradientDescent_Adapt.restype = optimization_status pLibDTSG.tsgGradientDescent_Const.argtypes = [type_optim_grad_fn_single, c_double, c_int, c_double, c_void_p, POINTER(c_int)] pLibDTSG.tsgGradientDescent_Const.restype = optimization_status class GradientDescentState: ''' Wrapper to class TasOptimization::GradientDescentState ''' def __init__(self, aX0, fInitialStepsize): ''' Constructs a new state with a given number of dimensions and particles. aX0 : a one-dimensional NumPy array representing the starting point. fInitialStepsize : initial adaptive stepsize. ''' self.TasmanianGradientDescentState = True if (len(aX0.shape) != 1): raise InputError("aX0", "aX0 should be one-dimensional") self.pStatePntr = c_void_p(pLibDTSG.tsgGradientDescentState_Construct(aX0.shape[0], as_ctypes(aX0), fInitialStepsize)) def __del__(self): ''' Deletes an instance of the particle swarm state. ''' pLibDTSG.tsgGradientDescentState_Destruct(self.pStatePntr) def getNumDimensions(self): ''' Return the number of dimensions. ''' return pLibDTSG.tsgGradientDescentState_GetNumDimensions(self.pStatePntr) def getAdaptiveStepsize(self): ''' Return the adaptive stepsize. ''' return pLibDTSG.tsgGradientDescentState_GetAdaptiveStepsize(self.pStatePntr) def getX(self): ''' Return the current candidate point. ''' iNumDims = self.getNumDimensions() aResult = np.zeros((iNumDims,), np.float64) pLibDTSG.tsgGradientDescentState_GetX(self.pStatePntr, as_ctypes(aResult)) return aResult def setAdaptiveStepsize(self, fNewStepsize): ''' Set new adaptive stepsize fNewStepsize : a double representing the new adaptive stepsize. ''' pLibDTSG.tsgGradientDescentState_SetAdaptiveStepsize(self.pStatePntr, fNewStepsize) def setX(self, aXNew): ''' Set new particle positions from a NumPy array. aXNew : a one-dimensional NumPy array representing the new candidate point. ''' iNumDims = self.getNumDimensions() if (len(aXNew.shape) != 1): raise InputError("aXNew", "aXNew should be one-dimensional") if (aXNew.shape[0] != iNumDims): raise InputError("aXNew", "aXNew.shape[0] should match the number of dimensions") pLibDTSG.tsgGradientDescentState_SetX(self.pStatePntr, as_ctypes(aXNew)) # Helper methods for converting Python lambdas to C lambdas. def convert_py_obj_fn_single(pObjectiveFunction, sCallerName): def cpp_obj_fn(num_dim, x_single_ptr, err_arr): err_arr[0] = 1 aX = np.ctypeslib.as_array(x_single_ptr, (num_dim, )) aResult = pObjectiveFunction(aX) if not isinstance(aResult, float): print("ERROR: incorrect output from the objective function given to " + sCallerName + "(), should be a 'float' but received '" + type(aResult).__name__ + "'") return 0 err_arr[0] = 0 return aResult return cpp_obj_fn def convert_py_grad_fn_single(pGradientFunction, sCallerName): def cpp_grad_fn(num_dim, x_single_ptr, grad_ptr, err_arr): err_arr[0] = 1 aX = np.ctypeslib.as_array(x_single_ptr, (num_dim,)) aResult = pGradientFunction(aX) if aResult.shape != (num_dim, ): print("ERROR: incorrect output from the gradient function given to " + sCallerName + "(), should be a NumPy array with shape (iNumDims,)") return aGrad = np.ctypeslib.as_array(grad_ptr, (num_dim,)) aGrad[0:num_dim] = aResult[0:num_dim] err_arr[0] = 0 return cpp_grad_fn def convert_py_proj_fn_single(pProjectionFunction, sCallerName): def cpp_proj_fn(num_dim, x_single_ptr, proj_ptr, err_arr): err_arr[0] = 1 aX = np.ctypeslib.as_array(x_single_ptr, (num_dim, )) aResult = pProjectionFunction(aX) if aResult.shape != (num_dim, ): print("ERROR: incorrect output from the projection function given to " + sCallerName + "(), should be a NumPy array with shape (iNumDims,)") return aProj = np.ctypeslib.as_array(proj_ptr, (num_dim,)) aProj[0:num_dim] = aResult[0:num_dim] err_arr[0] = 0 return cpp_proj_fn # Main algorithms. def AdaptiveProjectedGradientDescent(pObjectiveFunction, pGradientFunction, pProjectionFunction, fIncreaseCoeff, fDecreaseCoeff, iMaxIterations, fTolerance, oGradientDescentState): ''' Wrapper around TasOptimization::GradientDescent(). Runs at most iMaxIterations of the adaptive stepsize projected gradient descent algorithm on an input state oGradientDescentState to minimize the function pObjectiveFunction with gradient pGradientFunction and projection function pProjectionFunction. The parameters fIncreaseCoeff and fDecreaseCoeff control the evolution of the algorithm. The parameter fTolerance is a first-order stationarity tolerance used for early termination (see the C++ documentation for more details). Returns a dictionary containing the results of the run. pObjectiveFunction : a Python lambda representing the objective function; it should take in a one-dimensional NumPy array (x_single) and produce a double representing be the result of evaluating the objective function on x_single; it is expected that x_single.shape[0] = .getNumDimensions(). pGradientFunction : a Python lambda representing the gradient of the objective function; it should take in a one-dimensional NumPy array (x_single) and produce a one-dimensional NumPy representing the gradient (grad) at x_single; it is expected that x_single.shape[0] = grad.shape[0] = .getNumDimensions(). pProjectionFunction : a Python lambda representing the domain projection function; it should take in a one-dimensional NumPy array (x_single) and produce a one-dimensional NumPy representing the projection (proj) of x_single onto the domain; it is expected that x_single.shape[0] = proj.shape[0] = .getNumDimensions(). fIncreaseCoeff : a positive double controlling how fast the stepsize is increased; it is expected to be greater than 1. fDecreaseCoeff : a positive double controlling how fast the stepsize is decreased; it is expected to be greater than 1. iMaxIterations : a positive integer representing the maximum number iterations the algorithm is run. fTolerance : a positive double representing the stationarity tolerance for early tolerance. oGradientDescentState : an instance of the Python GradientDescentState class; it will contain the results of applying the algorithm. ''' cpp_obj_fn = convert_py_obj_fn_single(pObjectiveFunction, "GradientDescent") cpp_grad_fn = convert_py_grad_fn_single(pGradientFunction, "GradientDescent") cpp_proj_fn = convert_py_proj_fn_single(pProjectionFunction, "GradientDescent") pErrorCode = (c_int * 1)() oStatus = pLibDTSG.tsgGradientDescent_AdaptProj(type_optim_obj_fn_single(cpp_obj_fn), type_optim_grad_fn_single(cpp_grad_fn), type_optim_proj_fn_single(cpp_proj_fn), c_double(fIncreaseCoeff), c_double(fDecreaseCoeff), c_int(iMaxIterations), c_double(fTolerance), oGradientDescentState.pStatePntr, pErrorCode) if pErrorCode[0] != 0: raise InputError("GradientDescent", "An error occurred during the call to Tasmanian.") return clean_status(oStatus) def AdaptiveGradientDescent(pObjectiveFunction, pGradientFunction, fIncreaseCoeff, fDecreaseCoeff, iMaxIterations, fTolerance, oGradientDescentState): ''' Wrapper around TasOptimization::GradientDescent(). Runs at most iMaxIterations of the adaptive stepsize (unconstrained) gradient descent algorithm on an input state oGradientDescentState to minimize the function pObjectiveFunction with gradient pGradientFunction and projection function pProjectionFunction. The parameters fIncreaseCoeff and fDecreaseCoeff control the evolution of the algorithm. The parameter fTolerance is a first-order stationarity tolerance used for early termination (see the C++ documentation for more details). Returns a dictionary containing the results of the run. pObjectiveFunction : a Python lambda representing the objective function; it should take in a one-dimensional NumPy array (x_single) and produce a double representing be the result of evaluating the objective function on x_single; it is expected that x_single.shape[0] = .getNumDimensions(). pGradientFunction : a Python lambda representing the gradient of the objective function; it should take in a one-dimensional NumPy array (x_single) and produce a one-dimensional NumPy representing the gradient (grad) at x_single; it is expected that x_single.shape[0] = grad.shape[0] = .getNumDimensions(). fIncreaseCoeff : a positive double controlling how fast the stepsize is increased; it is expected to be greater than 1. fDecreaseCoeff : a positive double controlling how fast the stepsize is decreased; it is expected to be greater than 1. iMaxIterations : a positive integer representing the maximum number iterations the algorithm is run. fTolerance : a positive double representing the stationarity tolerance for early tolerance. oGradientDescentState : an instance of the Python GradientDescentState class; it will contain the results of applying the algorithm. ''' cpp_obj_fn = convert_py_obj_fn_single(pObjectiveFunction, "GradientDescent") cpp_grad_fn = convert_py_grad_fn_single(pGradientFunction, "GradientDescent") pErrorCode = (c_int * 1)() oStatus = pLibDTSG.tsgGradientDescent_Adapt(type_optim_obj_fn_single(cpp_obj_fn), type_optim_grad_fn_single(cpp_grad_fn), c_double(fIncreaseCoeff), c_double(fDecreaseCoeff), c_int(iMaxIterations), c_double(fTolerance), oGradientDescentState.pStatePntr, pErrorCode) if pErrorCode[0] != 0: raise InputError("GradientDescent", "An error occurred during the call to Tasmanian.") return clean_status(oStatus) def GradientDescent(pGradientFunction, fStepsize, iMaxIterations, fTolerance, oGradientDescentState): ''' Wrapper around TasOptimization::GradientDescent(). Runs at most iMaxIterations of the constant stepsize (unconstrained) gradient descent algorithm on an input state oGradientDescentState to minimize the function pObjectiveFunction with gradient pGradientFunction and projection function pProjectionFunction. The parameter fTolerance is a first-order stationarity tolerance used for early termination (see the C++ documentation for more details). Returns a dictionary containing the results of the run. pGradientFunction : a Python lambda representing the gradient of the objective function; it should take in a one-dimensional NumPy array (x_single) and produce a one-dimensional NumPy representing the gradient (grad) at x_single; it is expected that x_single.shape[0] = grad.shape[0] = .getNumDimensions(). fStepsize : a positive double representing the stepsize. iMaxIterations : a positive integer representing the maximum number iterations the algorithm is run. fTolerance : a positive double representing the stationarity tolerance for early tolerance. oGradientDescentState : an instance of the Python GradientDescentState class; it will contain the results of applying the algorithm. ''' cpp_grad_fn = convert_py_grad_fn_single(pGradientFunction, "GradientDescent") pErrorCode = (c_int * 1)() oStatus = pLibDTSG.tsgGradientDescent_Const(type_optim_grad_fn_single(cpp_grad_fn), c_double(fStepsize), c_int(iMaxIterations), c_double(fTolerance), oGradientDescentState.pStatePntr, pErrorCode) if pErrorCode[0] != 0: raise InputError("GradientDescent", "An error occurred during the call to Tasmanian.") return clean_status(oStatus) TASMANIAN-8.1/InterfacePython/TasmanianOPT.py000066400000000000000000000047711470551176200206700ustar00rootroot00000000000000# Copyright (c) 2022, Miroslav Stoyanov & Weiwei Kong # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND # IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF # THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL # ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES # RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING # FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. from TasmanianParticleSwarm import ParticleSwarmState, ParticleSwarm from TasmanianGradientDescent import GradientDescentState, AdaptiveProjectedGradientDescent, AdaptiveGradientDescent, GradientDescent TASMANIAN-8.1/InterfacePython/TasmanianParticleSwarm.py000066400000000000000000000424631470551176200230030ustar00rootroot00000000000000# Copyright (c) 2022, Miroslav Stoyanov & Weiwei Kong # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND # IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF # THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL # ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES # RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING # FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. from ctypes import c_char_p, c_int, c_double, c_void_p, POINTER, cdll, cast, CFUNCTYPE from numpy.ctypeslib import as_ctypes import numpy as np import sys from TasmanianConfig import __path_libdream__ from TasmanianConfig import TasmanianInputError as InputError import TasmanianDREAM as DREAM type_optim_obj_fn = CFUNCTYPE(None, c_int, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_int)) type_optim_dom_fn = CFUNCTYPE(c_int, c_int, POINTER(c_double), POINTER(c_int)) type_dream_random = CFUNCTYPE(c_double) pLibDTSG = cdll.LoadLibrary(__path_libdream__) pLibDTSG.tsgParticleSwarmState_Construct.restype = c_void_p pLibDTSG.tsgParticleSwarmState_Construct.argtypes = [c_int, c_int] pLibDTSG.tsgParticleSwarmState_Destruct.argtypes = [c_void_p] pLibDTSG.tsgParticleSwarmState_GetNumDimensions.restype = c_int pLibDTSG.tsgParticleSwarmState_GetNumDimensions.argtype = [c_void_p] pLibDTSG.tsgParticleSwarmState_GetNumParticles.restype = c_int pLibDTSG.tsgParticleSwarmState_GetNumParticles.argtype = [c_void_p] pLibDTSG.tsgParticleSwarmState_GetParticlePositions.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgParticleSwarmState_GetParticleVelocities.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgParticleSwarmState_GetBestParticlePositions.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgParticleSwarmState_GetBestPosition.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgParticleSwarmState_IsPositionInitialized.restype = c_int pLibDTSG.tsgParticleSwarmState_IsPositionInitialized.argtype = [c_void_p] pLibDTSG.tsgParticleSwarmState_IsVelocityInitialized.restype = c_int pLibDTSG.tsgParticleSwarmState_IsVelocityInitialized.argtype = [c_void_p] pLibDTSG.tsgParticleSwarmState_IsBestPositionInitialized.restype = c_int pLibDTSG.tsgParticleSwarmState_IsBestPositionInitialized.argtype = [c_void_p] pLibDTSG.tsgParticleSwarmState_IsCacheInitialized.restype = c_int pLibDTSG.tsgParticleSwarmState_IsCacheInitialized.argtype = [c_void_p] pLibDTSG.tsgParticleSwarmState_SetParticlePositions.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgParticleSwarmState_SetParticleVelocities.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgParticleSwarmState_SetBestParticlePositions.argtypes = [c_void_p, POINTER(c_double)] pLibDTSG.tsgParticleSwarmState_ClearBestParticles.argtypes = [c_void_p] pLibDTSG.tsgParticleSwarmState_ClearCache.argtypes = [c_void_p] pLibDTSG.tsgParticleSwarmState_InitializeParticlesInsideBox.argtypes = [c_void_p, POINTER(c_double), POINTER(c_double), c_char_p, c_int, type_dream_random] pLibDTSG.tsgParticleSwarm.argtypes = [type_optim_obj_fn, type_optim_dom_fn, c_double, c_double, c_double, c_int, c_void_p, c_char_p, c_int, type_dream_random, POINTER(c_int)] class ParticleSwarmState: ''' Wrapper to class TasOptimization::ParticleSwarmState ''' def __init__(self, iNumDimensions, iNumParticles): ''' Constructs a new state with a given number of dimensions and particles. iNumDimensions : positive integer indicating the number of dimensions. iNumParticles : positive integer indicating the number of particles. ''' self.TasmanianParticleSwarmState = True self.pStatePntr = c_void_p(pLibDTSG.tsgParticleSwarmState_Construct(iNumDimensions, iNumParticles)) def __del__(self): ''' Deletes an instance of the particle swarm state. ''' pLibDTSG.tsgParticleSwarmState_Destruct(self.pStatePntr) def getNumDimensions(self): ''' Return the number of dimensions. ''' return pLibDTSG.tsgParticleSwarmState_GetNumDimensions(self.pStatePntr) def getNumParticles(self): ''' Return the number of particles. ''' return pLibDTSG.tsgParticleSwarmState_GetNumParticles(self.pStatePntr) def getParticlePositions(self): ''' Return the particle positions as a 2D NumPy array. The shape of this array is (self.getNumParticles(), self.getNumDimensions()) and the i-th row if this array corresponds to the position of the i-th particle. ''' iNumDims = self.getNumDimensions() iNumPart = self.getNumParticles() aResult = np.zeros((iNumDims * iNumPart,), np.float64) pLibDTSG.tsgParticleSwarmState_GetParticlePositions(self.pStatePntr, as_ctypes(aResult)) return aResult.reshape((iNumPart, iNumDims)) def getParticleVelocities(self): ''' Return the particle velocities as a 2D NumPy array. The shape of this array is (self.getNumParticles(), self.getNumDimensions()) and the i-th row if this array corresponds to the velocity of the i-th particle. ''' iNumDims = self.getNumDimensions() iNumPart = self.getNumParticles() aResult = np.zeros((iNumDims * iNumPart,), np.float64) pLibDTSG.tsgParticleSwarmState_GetParticleVelocities(self.pStatePntr, as_ctypes(aResult)) return aResult.reshape((iNumPart, iNumDims)) def getBestParticlePositions(self): ''' Return the best particle positions as a 2D NumPy array. The shape of this array is (self.getNumParticles()+1 , self.getNumDimensions()) and the i-th row if this array corresponds to the best position of the i-th particle for the first .getNumParticles() particles. The last row corresponds to the best particle position of the swarm. ''' iNumDims = self.getNumDimensions() iNumPart = self.getNumParticles() aResult = np.zeros((iNumDims * (iNumPart + 1),), np.float64) pLibDTSG.tsgParticleSwarmState_GetBestParticlePositions(self.pStatePntr, as_ctypes(aResult)) return aResult.reshape((iNumPart + 1, iNumDims)) def getBestPosition(self): ''' Return the best particle position of the swarm as a 1D NumPy array. The size of the array is self.getNumDimensions(). ''' iNumDims = self.getNumDimensions() aResult = np.zeros((iNumDims,), np.float64) pLibDTSG.tsgParticleSwarmState_GetBestPosition(self.pStatePntr, as_ctypes(aResult)) return aResult def isPositionInitialized(self): ''' Returns True if the particle positions have been initialized and False otherwise. ''' return bool(pLibDTSG.tsgParticleSwarmState_IsPositionInitialized(self.pStatePntr)) def isVelocityInitialized(self): ''' Returns True if the particle velocities have been initialized and False otherwise. ''' return bool(pLibDTSG.tsgParticleSwarmState_IsVelocityInitialized(self.pStatePntr)) def isBestPositionInitialized(self): ''' Returns True if the best particle positions have been initialized and False otherwise. ''' return bool(pLibDTSG.tsgParticleSwarmState_IsBestPositionInitialized(self.pStatePntr)) def isCacheInitialized(self): ''' Returns True if the cache has been initialized and False otherwise. ''' return bool(pLibDTSG.tsgParticleSwarmState_IsCacheInitialized(self.pStatePntr)) def setParticlePositions(self, llfNewPPosns): ''' Set new particle positions from a NumPy array. llfNewPPosns : a two-dimensional numpy.ndarray with llfNewPPosns.shape[0] = self.getNumParticles() llfNewPPosns.shape[1] = self.getNumDimensions() ''' iNumPart = self.getNumParticles() iNumDims = self.getNumDimensions() if (llfNewPPosns.shape[0] != iNumPart): raise InputError("llfNewPPosns", "llfNewPPosns.shape[0] should match the number of particles") if (llfNewPPosns.shape[1] != iNumDims): raise InputError("llfNewPPosns", "llfNewPPosns.shape[1] should match the number of dimensions") llfNewPPosns.resize((iNumDims * iNumPart,)) pLibDTSG.tsgParticleSwarmState_SetParticlePositions(self.pStatePntr, as_ctypes(llfNewPPosns)) llfNewPPosns.resize((iNumPart, iNumDims)) def setParticleVelocities(self, llfNewPVelcs): ''' Set new particle velocities from a NumPy array. llfNewPVelcs : a two-dimensional numpy.ndarray with llfNewPVelcs.shape[0] = self.getNumParticles() llfNewPVelcs.shape[1] = self.getNumDimensions() ''' iNumPart = self.getNumParticles() iNumDims = self.getNumDimensions() if (llfNewPVelcs.shape[0] != iNumPart): raise InputError("llfNewPVelcs", "llfNewPVelcs.shape[0] should match the number of particles") if (llfNewPVelcs.shape[1] != iNumDims): raise InputError("llfNewPVelcs", "llfNewPVelcs.shape[1] should match the number of dimensions") llfNewPVelcs.resize((iNumDims * iNumPart,)) pLibDTSG.tsgParticleSwarmState_SetParticleVelocities(self.pStatePntr, as_ctypes(llfNewPVelcs)) llfNewPVelcs.resize((iNumPart, iNumDims)) def setBestParticlePositions(self, llfNewBPPosns): ''' Set new best particle positions from a NumPy array. llfNewBPPosns : a two-dimensional numpy.ndarray with llfNewPVelcs.shape[0] = self.getNumParticles() + 1 llfNewPVelcs.shape[1] = self.getNumDimensions() ''' iNumPart = self.getNumParticles() iNumDims = self.getNumDimensions() if (llfNewBPPosns.shape[0] != iNumPart + 1): raise InputError("llfNewBPPosns", "llfNewBPPosns.shape[0] should match the number of particles + 1") if (llfNewBPPosns.shape[1] != iNumDims): raise InputError("llfNewBPPosns", "llfNewBPPosns.shape[1] should match the number of dimensions") llfNewBPPosns.resize(((iNumPart + 1) * iNumDims,)) pLibDTSG.tsgParticleSwarmState_SetBestParticlePositions(self.pStatePntr, as_ctypes(llfNewBPPosns)) llfNewBPPosns.resize((iNumPart + 1, iNumDims)) def clearBestParticles(self): ''' Clears the vector of best particles. ''' pLibDTSG.tsgParticleSwarmState_ClearBestParticles(self.pStatePntr) def clearCache(self): ''' Clears the internal cache of the managed ParticleSwarm C++ object. ''' pLibDTSG.tsgParticleSwarmState_ClearCache(self.pStatePntr) def initializeParticlesInsideBox(self, lfBoxLower, lfBoxUpper, random01 = DREAM.RandomGenerator(sType = "default")): ''' Initialize the particle swarm state with randomized particles (determined by gen_random01) inside a box bounded by the parameters box_lower and box_upper. The i-th entry in these parameters respectively represent the lower and upper bounds on the particle position values for the i-th dimension. The parameter random01 controls the distribution of the particles. lfBoxLower : a one-dimensional NumPy array with lfBoxLower.shape[0] = self.getNumDimensions() lfBoxUpper : a one-dimensional NumPy array with lfBoxLower.shape[0] = self.getNumDimensions() random01 : a DREAM.RandomGenerator instance that produces floats in [0,1] ''' iNumDims = self.getNumDimensions() if (lfBoxLower.shape != (iNumDims,)): raise InputError("lfBoxLower", "lfBoxLower.shape should be (self.getNumDimensions(),)") if (lfBoxUpper.shape != (iNumDims,)): raise InputError("lfBoxUpper", "lfBoxUpper.shape should be (self.getNumDimensions(),)") pLibDTSG.tsgParticleSwarmState_InitializeParticlesInsideBox(self.pStatePntr, as_ctypes(lfBoxLower), as_ctypes(lfBoxUpper), c_char_p(random01.sType), c_int(random01.iSeed), type_dream_random(random01.pCallable)) def ParticleSwarm(pObjectiveFunction, pInside, fInertiaWeight, fCognitiveCoeff, fSocialCoeff, iNumIterations, oParticleSwarmState, random01 = DREAM.RandomGenerator(sType = "default")): ''' Wrapper around TasOptimization::ParticleSwarm(). Runs iNumIterations of the particle swarm algorithm on an input state cParticleSwarmState to minimize the function pObjectiveFunction over a domain specified by pInside. The parameters fInertiaWeight, fCognitiveCoeff, and fSocialCoeff control the evolution of the algorithm. The parameter random01 controls the distribution of the particles. pObjectiveFunction : a Python lambda representing the objective function; it should take in one 2D NumPy array (x_batch) and produce a 1D NumPy array, sized (iNumBatch,), whose i-th entry should be the result of evaluating the objective function to x_batch[i,:]; it is expected that x_batch.shape[1] = .getNumDimensions(). pInside : a Python lambda representing the function domain; it should take in a 1D NumPy array (x) and produce a Boolean (isInside); when called, it should return True if x is in the domain and False otherwise; it is expected that x.shape[0] = .getNumDimensions(). fInertiaWeight : a double that controls the speed of the particles; should be in (0,1). fCognitiveCoeff : a double that controls how much a particle favors its own trajectory; usually in [1,3]. fSocialCoeff : a double that controls how much a particle favors the swarm's trajectories; usually in [1,3]. iNumIterations : a positive integer representing the number iterations the algorithm is run. oParticleSwarmState : an instance of the Python ParticleSwarmState class; it will contain the results of applying the algorithm. random01 : (optional) a DREAM.RandomGenerator instance that produces floats in [0,1] ''' def cpp_obj_fn(num_dim, num_batch, x_batch_ptr, fval_ptr, err_arr): err_arr[0] = 1 aX = np.ctypeslib.as_array(x_batch_ptr, (num_batch, num_dim)) aResult = pObjectiveFunction(aX) if aResult.shape != (num_batch, ): print("ERROR: incorrect output from the objective function given to ParticleSwarm(), should be a NumPy array with shape (iNumBatch,)") return aFVal = np.ctypeslib.as_array(fval_ptr, (num_batch,)) aFVal[0:num_batch] = aResult[0:num_batch] err_arr[0] = 0 def cpp_dom_fn(num_dim, x_ptr, err_arr): err_arr[0] = 1 aX = np.ctypeslib.as_array(x_ptr, (num_dim,)) iResult = pInside(aX) if not isinstance(iResult, bool): print("ERROR: incorrect output from the domain function given to ParticleSwarm(), should be a 'bool' but received '" + type(iResult).__name__ + "'") return False err_arr[0] = 0 return iResult pErrorCode = (c_int * 1)() pLibDTSG.tsgParticleSwarm(type_optim_obj_fn(cpp_obj_fn), type_optim_dom_fn(cpp_dom_fn), c_double(fInertiaWeight), c_double(fCognitiveCoeff), c_double(fSocialCoeff), c_int(iNumIterations), oParticleSwarmState.pStatePntr, c_char_p(random01.sType), c_int(random01.iSeed), type_dream_random(random01.pCallable), pErrorCode) if pErrorCode[0] != 0: raise InputError("ParticleSwarm", "An error occurred during the call to Tasmanian.") TASMANIAN-8.1/InterfacePython/TasmanianSG.py000066400000000000000000003632211470551176200205350ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from ctypes import c_char_p, c_int, c_double, c_void_p, POINTER, CDLL, create_string_buffer, RTLD_GLOBAL import numpy as np import sys from TasmanianConfig import TasmanianInputError, __path_libsparsegrid__ pLibTSG = CDLL(__path_libsparsegrid__, mode = RTLD_GLOBAL) # The ctypes library requires that we manually specify the return types of functions. In C, this is done by header files, so the # declarations below serve as a header. # Return types for TasmanianSparseGrid C class methods. pLibTSG.tsgConstructTasmanianSparseGrid.restype = c_void_p pLibTSG.tsgGetVersion.restype = c_char_p pLibTSG.tsgGetLicense.restype = c_char_p pLibTSG.tsgGetVersionMajor.restype = c_int pLibTSG.tsgGetVersionMinor.restype = c_int pLibTSG.tsgIsOpenMPEnabled.restype = c_int pLibTSG.tsgIsCudaEnabled.restype = c_int pLibTSG.tsgIsHipEnabled.restype = c_int pLibTSG.tsgIsDpcppEnabled.restype = c_int pLibTSG.tsgGetNumDimensions.restype = c_int pLibTSG.tsgGetNumOutputs.restype = c_int pLibTSG.tsgGetNumLoaded.restype = c_int pLibTSG.tsgGetNumNeeded.restype = c_int pLibTSG.tsgGetNumPoints.restype = c_int pLibTSG.tsgRead.restype = c_int pLibTSG.tsgGetAlpha.restype = c_double pLibTSG.tsgGetBeta.restype = c_double pLibTSG.tsgGetOrder.restype = c_int pLibTSG.tsgGetCustomRuleDescription.restype = c_char_p pLibTSG.tsgGetSubrules.restype = c_void_p pLibTSG.tsgGetLoadedPoints.restype = POINTER(c_double) pLibTSG.tsgGetNeededPoints.restype = POINTER(c_double) pLibTSG.tsgGetPoints.restype = POINTER(c_double) pLibTSG.tsgBatchGetInterpolationWeights.restype = POINTER(c_double) pLibTSG.tsgIsSetDomainTransfrom.restype = c_int pLibTSG.tsgIsSetConformalTransformASIN.restype = c_int pLibTSG.tsgEvaluateSparseHierarchicalFunctionsGetNZ.restype = c_int pLibTSG.tsgIsUsingConstruction.restype = c_int pLibTSG.tsgGetCandidateConstructionPointsVoidPntr.restype = c_void_p pLibTSG.tsgGetCandidateConstructionPointsSurplusVoidPntr.restype = c_void_p pLibTSG.tsgGetCandidateConstructionPointsPythonGetNP.restype = c_int pLibTSG.tsgGetAccelerationType.restype = c_char_p pLibTSG.tsgIsAccelerationAvailable.restype = c_int pLibTSG.tsgGetGPUID.restype = c_int pLibTSG.tsgGetNumGPUs.restype = c_int pLibTSG.tsgGetGPUMemory.restype = c_int # Argument types for TasmanianSparseGrid C class methods. pLibTSG.tsgDestructTasmanianSparseGrid.argtypes = [c_void_p] pLibTSG.tsgCopySubGrid.argtypes = [c_void_p, c_void_p, c_int, c_int] pLibTSG.tsgWrite.argtypes = [c_void_p, c_char_p] pLibTSG.tsgWriteBinary.argtypes = [c_void_p, c_char_p] pLibTSG.tsgRead.argtypes = [c_void_p, c_char_p] pLibTSG.tsgMakeGlobalGrid.argtypes = [c_void_p, c_int, c_int, c_int, c_char_p, c_char_p, POINTER(c_int), c_double, c_double, c_char_p, POINTER(c_int)] pLibTSG.tsgMakeSequenceGrid.argtypes = [c_void_p, c_int, c_int, c_int, c_char_p, c_char_p, POINTER(c_int), POINTER(c_int)] pLibTSG.tsgMakeLocalPolynomialGrid.argtypes = [c_void_p, c_int, c_int, c_int, c_int, c_char_p, POINTER(c_int)] pLibTSG.tsgMakeWaveletGrid.argtypes = [c_void_p, c_int, c_int, c_int, c_int, POINTER(c_int)] pLibTSG.tsgMakeFourierGrid.argtypes = [c_void_p, c_int, c_int, c_int, c_char_p, POINTER(c_int), POINTER(c_int)] pLibTSG.tsgMakeGridFromCustomTabulated.argtypes = [c_void_p, c_int, c_int, c_int, c_char_p, c_void_p, POINTER(c_int), POINTER(c_int)] pLibTSG.tsgUpdateGlobalGrid.argtypes = [c_void_p, c_int, c_char_p, POINTER(c_int), POINTER(c_int)] pLibTSG.tsgUpdateSequenceGrid.argtypes = [c_void_p, c_int, c_char_p, POINTER(c_int), POINTER(c_int)] pLibTSG.tsgUpdateFourierGrid.argtypes = [c_void_p, c_int, c_char_p, POINTER(c_int), POINTER(c_int)] pLibTSG.tsgGetAlpha.argtypes = [c_void_p] pLibTSG.tsgGetBeta.argtypes = [c_void_p] pLibTSG.tsgGetOrder.argtypes = [c_void_p] pLibTSG.tsgGetNumDimensions.argtypes = [c_void_p] pLibTSG.tsgGetNumOutputs.argtypes = [c_void_p] pLibTSG.tsgCopyRuleChars.argtypes = [c_void_p, c_int, c_char_p, POINTER(c_int)] # char is not really const pLibTSG.tsgGetCustomRuleDescription.argtypes = [c_void_p] pLibTSG.tsgGetSubrules.argtypes = [c_void_p, c_int, c_int, c_char_p] pLibTSG.tsgGetNumLoaded.argtypes = [c_void_p] pLibTSG.tsgGetNumNeeded.argtypes = [c_void_p] pLibTSG.tsgGetNumPoints.argtypes = [c_void_p] pLibTSG.tsgGetLoadedPoints.argtypes = [c_void_p] pLibTSG.tsgGetNeededPoints.argtypes = [c_void_p] pLibTSG.tsgGetPoints.argtypes = [c_void_p] pLibTSG.tsgGetLoadedPointsStatic.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgGetNeededPointsStatic.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgGetPointsStatic.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgGetQuadratureWeightsStatic.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgGetInterpolationWeightsStatic.argtypes = [c_void_p, POINTER(c_double), POINTER(c_double)] pLibTSG.tsgLoadNeededValues.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgGetLoadedValuesStatic.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgEvaluate.argtypes = [c_void_p, POINTER(c_double), POINTER(c_double)] pLibTSG.tsgEvaluateFast.argtypes = [c_void_p, POINTER(c_double), POINTER(c_double)] pLibTSG.tsgIntegrate.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgDifferentiate.argtypes = [c_void_p, POINTER(c_double), POINTER(c_double)] pLibTSG.tsgEvaluateBatch.argtypes = [c_void_p, POINTER(c_double), c_int, POINTER(c_double)] pLibTSG.tsgBatchGetInterpolationWeights.argtypes = [c_void_p, POINTER(c_double), c_int] pLibTSG.tsgBatchGetInterpolationWeightsStatic.argtypes = [c_void_p, POINTER(c_double), c_int, POINTER(c_double)] pLibTSG.tsgIsGlobal.argtypes = [c_void_p] pLibTSG.tsgIsSequence.argtypes = [c_void_p] pLibTSG.tsgIsLocalPolynomial.argtypes = [c_void_p] pLibTSG.tsgIsWavelet.argtypes = [c_void_p] pLibTSG.tsgIsFourier.argtypes = [c_void_p] pLibTSG.tsgSetDomainTransform.argtypes = [c_void_p, POINTER(c_double), POINTER(c_double)] pLibTSG.tsgIsSetDomainTransfrom.argtypes = [c_void_p] pLibTSG.tsgClearDomainTransform.argtypes = [c_void_p] pLibTSG.tsgGetDomainTransform.argtypes = [c_void_p, POINTER(c_double), POINTER(c_double)] pLibTSG.tsgSetConformalTransformASIN.argtypes = [c_void_p, POINTER(c_int)] pLibTSG.tsgIsSetConformalTransformASIN.argtypes = [c_void_p] pLibTSG.tsgClearConformalTransform.argtypes = [c_void_p] pLibTSG.tsgGetConformalTransformASIN.argtypes = [c_void_p, POINTER(c_int)] pLibTSG.tsgClearLevelLimits.argtypes = [c_void_p] pLibTSG.tsgGetLevelLimits.argtypes = [c_void_p, POINTER(c_int)] pLibTSG.tsgSetAnisotropicRefinement.argtypes = [c_void_p, c_char_p, c_int, c_int, POINTER(c_int)] pLibTSG.tsgEstimateAnisotropicCoefficientsStatic.argtypes = [c_void_p, c_char_p, c_int, POINTER(c_int)] pLibTSG.tsgSetGlobalSurplusRefinement.argtypes = [c_void_p, c_double, c_int, POINTER(c_int)] pLibTSG.tsgSetLocalSurplusRefinement.argtypes = [c_void_p, c_double, c_char_p, c_int, POINTER(c_int), POINTER(c_double)] pLibTSG.tsgClearRefinement.argtypes = [c_void_p] pLibTSG.tsgMergeRefinement.argtypes = [c_void_p] pLibTSG.tsgRemovePointsByHierarchicalCoefficient.argtypes = [c_void_p, c_double, c_int, POINTER(c_double)] pLibTSG.tsgRemovePointsByHierarchicalCoefficientHardCutoff.argtypes = [c_void_p, c_int, c_int, POINTER(c_double)] pLibTSG.tsgEvaluateHierarchicalFunctions.argtypes = [c_void_p, POINTER(c_double), c_int, POINTER(c_double)] pLibTSG.tsgGetHierarchicalSupportStatic.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgSetHierarchicalCoefficients.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgEvaluateSparseHierarchicalFunctionsGetNZ.argtypes = [c_void_p, POINTER(c_double), c_int] pLibTSG.tsgEvaluateSparseHierarchicalFunctionsStatic.argtypes = [c_void_p, POINTER(c_double), c_int, POINTER(c_int), POINTER(c_int), POINTER(c_double)] pLibTSG.tsgGetHierarchicalCoefficientsStatic.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgIntegrateHierarchicalFunctionsStatic.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgBeginConstruction.argtypes = [c_void_p] pLibTSG.tsgIsUsingConstruction.argtypes = [c_void_p] pLibTSG.tsgGetCandidateConstructionPointsVoidPntr.argtypes = [c_void_p, c_char_p, c_int, POINTER(c_int), POINTER(c_int)] pLibTSG.tsgGetCandidateConstructionPointsSurplusVoidPntr.argtypes = [c_void_p, c_double, c_char_p, c_int, POINTER(c_int), POINTER(c_double)] pLibTSG.tsgGetCandidateConstructionPointsPythonGetNP.argtypes = [c_void_p, c_void_p] pLibTSG.tsgGetCandidateConstructionPointsPythonStatic.argtypes = [c_void_p, POINTER(c_double)] pLibTSG.tsgGetCandidateConstructionPointsPythonDeleteVect.argtypes = [c_void_p] pLibTSG.tsgLoadConstructedPoint.argtypes = [c_void_p, POINTER(c_double), c_int, POINTER(c_double)] pLibTSG.tsgFinishConstruction.argtypes = [c_void_p] pLibTSG.tsgPrintStats.argtypes = [c_void_p] pLibTSG.tsgEnableAcceleration.argtypes = [c_void_p, c_char_p] pLibTSG.tsgEnableAccelerationGPU.argtypes = [c_void_p, c_char_p, c_int] pLibTSG.tsgGetAccelerationType.argtypes = [c_void_p] pLibTSG.tsgIsAccelerationAvailable.argtypes = [c_char_p] pLibTSG.tsgSetGPUID.argtypes = [c_void_p, c_int] pLibTSG.tsgGetGPUID.argtypes = [c_void_p] pLibTSG.tsgGetGPUMemory.argtypes = [c_int] pLibTSG.tsgGetGPUName.argtypes = [c_int, c_int, c_char_p, POINTER(c_int)] # not really const here # Return types for CustomTabulated C class methods. pLibTSG.tsgConstructCustomTabulated.restype = c_void_p; pLibTSG.tsgReadCustomTabulated.restype = c_int pLibTSG.tsgGetNumLevelsCustomTabulated.restype = c_int; pLibTSG.tsgGetNumPointsCustomTabulated.restype = c_int; pLibTSG.tsgGetIExactCustomTabulated.restype = c_int; pLibTSG.tsgGetQExactCustomTabulated.restype = c_int; pLibTSG.tsgGetDescriptionCustomTabulated.restype = c_char_p; pLibTSG.tsgMakeCustomTabulatedFromData.restype = c_void_p; # Argument types for CustomTabulated C class methods. pLibTSG.tsgDestructCustomTabulated.argtypes = [c_void_p]; pLibTSG.tsgReadCustomTabulated.argtypes = [c_void_p, c_char_p] pLibTSG.tsgWriteCustomTabulated.argtypes = [c_void_p, c_char_p] pLibTSG.tsgGetNumLevelsCustomTabulated.argtypes = [c_void_p]; pLibTSG.tsgGetNumPointsCustomTabulated.argtypes = [c_void_p, c_int]; pLibTSG.tsgGetIExactCustomTabulated.argtypes = [c_void_p, c_int]; pLibTSG.tsgGetQExactCustomTabulated.argtypes = [c_void_p, c_int]; pLibTSG.tsgGetDescriptionCustomTabulated.argtypes = [c_void_p]; pLibTSG.tsgGetWeightsNodesStaticCustomTabulated.argtypes = [c_void_p, c_int, POINTER(c_double), POINTER(c_double)] pLibTSG.tsgMakeCustomTabulatedFromData.argtype = [c_int, POINTER(c_int), POINTER(c_int), POINTER(c_double), POINTER(c_double), c_char_p] # Specifications for other C functions. pLibTSG.tsgPythonGetGlobalPolynomialSpace.restype = POINTER(c_int) pLibTSG.tsgPythonGetGlobalPolynomialSpace.argtypes = [c_void_p, c_int, POINTER(c_int)] pLibTSG.tsgDeleteInts.argtypes = [POINTER(c_int)] bTsgPlotting = True try: import matplotlib.pyplot as tsgPlot except: bTsgPlotting = False tsgPlot = [] lsTsgGlobalRules = ["clenshaw-curtis", "clenshaw-curtis-zero", "chebyshev", "chebyshev-odd", "gauss-legendre", "gauss-legendre-odd", "gauss-patterson", "leja", "leja-odd", "rleja", "rleja-odd", "rleja-double2", "rleja-double4", "rleja-shifted", "rleja-shifted-even", "rleja-shifted-double", "max-lebesgue", "max-lebesgue-odd", "min-lebesgue", "min-lebesgue-odd", "min-delta", "min-delta-odd", "gauss-chebyshev1", "gauss-chebyshev1-odd", "gauss-chebyshev2", "gauss-chebyshev2-odd", "fejer2", "gauss-gegenbauer", "gauss-gegenbauer-odd", "gauss-jacobi", "gauss-jacobi-odd", "gauss-laguerre", "gauss-laguerre-odd", "gauss-hermite", "gauss-hermite-odd", "custom-tabulated"] lsTsgGlobalTypes = ["level", "curved", "iptotal", "ipcurved", "qptotal", "qpcurved", "hyperbolic", "iphyperbolic", "qphyperbolic", "tensor", "iptensor", "qptensor"] lsTsgCurvedTypes = ["curved", "ipcurved", "qpcurved"] lsTsgRefineTypes = ["classic", "parents", "direction", "fds", "stable"] lsTsgSequenceRules = ["leja", "rleja", "rleja-shifted", "max-lebesgue", "min-lebesgue", "min-delta"] lsTsgLocalRules = ["localp", "semi-localp", "localp-zero", "localp-boundary"] lsTsgAccelTypes = ["none", "cpu-blas", "gpu-default", "gpu-cublas", "gpu-cuda", "gpu-rocblas", "gpu-hip", "gpu-magma"] class TasmanianSimpleSparseMatrix: def __init__(self): self.aPntr = [] self.aIndx = [] self.aVals = [] self.iNumRows = 0 self.iNumCols = 0 def getDenseForm(self): if ((self.iNumRows == 0) or (self.iNumCols == 0)): return np.empty([0,0], np.float64) aMat = np.zeros([self.iNumRows, self.iNumCols], np.float64 if not np.iscomplexobj(self.aVals) else np.complex128) for iI in range(self.iNumRows): iJ = self.aPntr[iI] while(iJ < self.aPntr[iI+1]): aMat[iI, self.aIndx[iJ]] = self.aVals[iJ] iJ += 1 return aMat class TasmanianSparseGrid: def __init__(self): ''' constructor, creates an empty grid instance ''' self.TasmanianSparseGridObject = True self.pGrid = pLibTSG.tsgConstructTasmanianSparseGrid() def __del__(self): ''' destructor, calls the C++ destructor and releases all memory used by this instance of the class Make sure to call this to avoid memory leaks ''' pLibTSG.tsgDestructTasmanianSparseGrid(self.pGrid) def stringBufferToString(self, pName, iNumChars): S = [s for s in pName] sName = "" for iI in range(iNumChars): sName += str(S[iI], encoding='utf8') return sName def getVersion(self): ''' returns the hardcoded version string from the library ''' return str(pLibTSG.tsgGetVersion(), encoding='utf8') def getLicense(self): ''' returns the hardcoded license string from the library ''' return str(pLibTSG.tsgGetLicense(), encoding='utf8') def getVersionMajor(self): ''' returns the hardcoded version major int ''' return pLibTSG.tsgGetVersionMajor() def getVersionMinor(self): ''' returns the hardcoded version minor int ''' return pLibTSG.tsgGetVersionMinor() def isOpenMPEnabled(self): ''' returns True if the library has been compiled with OpenMP support ''' return (pLibTSG.tsgIsOpenMPEnabled() != 0) def isCudaEnabled(self): ''' returns True if the library has been compiled with CUDA support ''' return (pLibTSG.tsgIsCudaEnabled() != 0) def isHipEnabled(self): ''' returns True if the library has been compiled with HIP support ''' return (pLibTSG.tsgIsHipEnabled() != 0) def isDpcppEnabled(self): ''' returns True if the library has been compiled with DPC++ support ''' return (pLibTSG.tsgIsDpcppEnabled() != 0) def read(self, sFilename): ''' reads the grid from a file discards any existing grid held by this class sFilename: string indicating a grid file where a grid was already written using write from Python or any other Tasmanian interface output: boolean True: the read was successful False: the read failed, check the CLI output for an error message ''' if pLibTSG.tsgRead(self.pGrid, bytes(sFilename, encoding='utf8')) == 0: raise TasmanianInputError("sFilename", "ERROR: {0:1s} does not appear to be a valid Tasmanian file.".format(sFilename)) def write(self, sFilename, bUseBinaryFormat = True): ''' writes the grid to a file sFilename: string indicating a grid file where a grid will be written bUseBinaryFormat: boolean True: write to a binary file False: write to an ASCII file ''' if (bUseBinaryFormat): pLibTSG.tsgWriteBinary(self.pGrid, bytes(sFilename, encoding='utf8')) else: pLibTSG.tsgWrite(self.pGrid, bytes(sFilename, encoding='utf8')) def makeGlobalGrid(self, iDimension, iOutputs, iDepth, sType, sRule, liAnisotropicWeights=[], fAlpha=0.0, fBeta=0.0, sCustomFilename="", liLevelLimits=[]): ''' creates a new sparse grid using a global rule discards any existing grid held by this class iDimension: int (positive) the number of inputs iOutputs: int (non-negative) the number of outputs iDepth: int (non-negative) controls the density of the grid, i.e., the offset for the tensor selection, the meaning of iDepth depends on sType Example 1: sType == 'iptotal' will give a grid that interpolates exactly all polynomials of degree up to and including iDepth Example 2: sType == 'qptotal' will give a grid that integrates exactly all polynomials of degree up to and including iDepth sType: string identifying the tensor selection strategy 'level' 'curved' 'hyperbolic' 'tensor' 'iptotal' 'ipcurved' 'iphyperbolic' 'iptensor' 'qptotal' 'qpcurved' 'qphyperbolic' 'qptensor' sRule: string (defines the 1-D rule that induces the grid) Interpolation rules Note: the quadrature induced by those rules is constructed by integrating the interpolant 'clenshaw-curtis' 'clenshaw-curtis-zero' 'fejer2' 'rleja' 'rleja-odd' 'rleja-double2' 'rleja-double4' 'rleja-shifted' 'rleja-shifted-even' 'max-lebesgue' 'max-lebesgue-odd' 'min-lebesgue' 'min-lebesgue-odd' 'leja' 'leja-odd' 'min-delta' 'min-delta-odd' 'chebyshev' 'chebyshev-odd' approximation using roots of Chebyshev polynomials non-nested case (in contrast to Clenshaw-Curtis nodes) Quadrature rules, the weights target exactness with respect to the highest polynomial degree possible 'gauss-legendre' 'gauss-legendre-odd' approximation using roots of polynomials orthogonal in measure Uniform 'gauss-patterson' (a.k.a. nested Gauss-Legendre) Note: the nodes and weights are hard-coded hence there is a limit on the highest possible depth 'gauss-chebyshev1' 'gauss-chebyshev1-odd' 'gauss-chebyshev2' 'gauss-chebyshev2-odd' approximation using roots of polynomials orthogonal in measures 1/sqrt(1-x^2) and sqrt(1-x^2) (respectively) 'gauss-gegenbauer' 'gauss-gegenbauer-odd' approximation using roots of polynomials orthogonal in measure (1-x^2)^alpha 'gauss-jacobi' approximation using roots of polynomials orthogonal in measure (1-x)^alpha * (1+x)^beta 'gauss-laguerre' approximation using roots of polynomials orthogonal in measure x^alpha * epx(-x) 'gauss-hermite' 'gauss-hermite-odd' approximation using roots of polynomials orthogonal in measure |x|^alpha * epx(-x^2) liAnisotropicWeights: list or numpy.ndarray of weights length must be iDimension or 2*iDimension the first iDimension weights must be positive see the manual for details fAlpha, fBeta: floats fAlpha : the alpha parameter for Gegenbauer, Jacobi, Hermite and Laguerre rules fBeta : the beta parameter for Jacobi rules sCustomRule: string giving the path to the file with custom-tabulated rule ''' if (iDimension <= 0): raise TasmanianInputError("iDimension", "ERROR: dimension should be a positive integer") if (iOutputs < 0): raise TasmanianInputError("iOutputs", "ERROR: outputs should be a non-negative integer") if (iDepth < 0): raise TasmanianInputError("iDepth", "ERROR: depth should be a non-negative integer") if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see TasmanianSG.lsTsgGlobalTypes for list of accepted types") if (sRule not in lsTsgGlobalRules): raise TasmanianInputError("sRule", "ERROR: invalid global rule, see TasmanianSG.lsTsgGlobalRules for list of accepted global rules") pAnisoWeights = None if (len(liAnisotropicWeights) > 0): if (sType in lsTsgCurvedTypes): iNumWeights = 2*iDimension else: iNumWeights = iDimension if (len(liAnisotropicWeights) != iNumWeights): raise TasmanianInputError("liAnisotropicWeights", "ERROR: wrong number of liAnisotropicWeights, sType '{0:s}' needs {1:1d} weights but len(liAnisotropicWeights) == {2:1d}".format(sType, iNumWeights, len(liAnisotropicWeights))) else: aAWeights = np.array([liAnisotropicWeights[i] for i in range(iNumWeights)], np.int32) pAnisoWeights = np.ctypeslib.as_ctypes(aAWeights) pCustomRule = bytes(sCustomFilename, encoding='utf8') if sCustomFilename else None pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgMakeGlobalGrid(self.pGrid, iDimension, iOutputs, iDepth, bytes(sType, encoding='utf8'), bytes(sRule, encoding='utf8'), pAnisoWeights, c_double(fAlpha), c_double(fBeta), pCustomRule, pLevelLimits) def makeSequenceGrid(self, iDimension, iOutputs, iDepth, sType, sRule, liAnisotropicWeights=[], liLevelLimits=[]): ''' creates a new sparse grid using a sequence rule discards any existing grid held by this class iDimension: int (positive) the number of inputs iOutputs: int (non-negative) the number of outputs iDepth: int (non-negative) controls the density of the grid, i.e., the offset for the tensor selection, the meaning of iDepth depends on sType Example 1: sType == 'iptotal' will give a grid that interpolates exactly all polynomials of degree up to and including iDepth Example 2: sType == 'qptotal' will give a grid that integrates exactly all polynomials of degree up to and including iDepth sType: string identifying the tensor selection strategy 'level' 'curved' 'hyperbolic' 'tensor' 'iptotal' 'ipcurved' 'iphyperbolic' 'iptensor' 'qptotal' 'qpcurved' 'qphyperbolic' 'qptensor' sRule: string (defines the 1-D rule that induces the grid) 'leja' 'rleja' 'rleja-shifted' 'max-lebesgue' 'min-lebesgue' 'min-delta' liAnisotropicWeights: list or numpy.ndarray of weights length must be iDimension or 2*iDimension the first iDimension weights must be positive see the manual for details ''' if (iDimension <= 0): raise TasmanianInputError("iDimension", "ERROR: dimension should be a positive integer") if (iOutputs < 0): raise TasmanianInputError("iOutputs", "ERROR: outputs should be a non-negative integer") if (iDepth < 0): raise TasmanianInputError("iDepth", "ERROR: depth should be a non-negative integer") if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see TasmanianSG.lsTsgGlobalTypes for list of accepted types") if (sRule not in lsTsgSequenceRules): raise TasmanianInputError("sRule", "ERROR: invalid sequence rule, see TasmanianSG.lsTsgSequenceRules for list of accepted sequence rules") pAnisoWeights = None if (len(liAnisotropicWeights) > 0): if (sType in lsTsgCurvedTypes): iNumWeights = 2*iDimension else: iNumWeights = iDimension if (len(liAnisotropicWeights) != iNumWeights): raise TasmanianInputError("liAnisotropicWeights", "ERROR: wrong number of liAnisotropicWeights, sType '{0:s}' needs {1:1d} weights but len(liAnisotropicWeights) == {2:1d}".format(sType, iNumWeights, len(liAnisotropicWeights))) else: pAnisoWeights = (c_int*iNumWeights)() for iI in range(iNumWeights): pAnisoWeights[iI] = liAnisotropicWeights[iI] pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgMakeSequenceGrid(self.pGrid, iDimension, iOutputs, iDepth, bytes(sType, encoding='utf8'), bytes(sRule, encoding='utf8'), pAnisoWeights, pLevelLimits) def makeLocalPolynomialGrid(self, iDimension, iOutputs, iDepth, iOrder=1, sRule="localp", liLevelLimits=[]): ''' creates a new sparse grid using a local polynomial rule discards any existing grid held by this class iDimension: int (positive) the number of inputs iOutputs: int (non-negative) the number of outputs iDepth: int (non-negative) controls the density of the grid, i.e., the number of levels to use iOrder: int (must be -1 or bigger) -1 indicates largest possible order 1 means linear, 2 means quadratic, etc. 0 means piece-wise constant, it has different hierarchy then the other orders, most notably the 1D rule triples the number of points per level (as opposed to double for the other cases) sRule: string (defines the 1-D rule that induces the grid) 'localp' 'localp-zero' 'semi-localp' 'localp-boundary' ''' if (iDimension <= 0): raise TasmanianInputError("iDimension", "ERROR: dimension should be a positive integer") if (iOutputs < 0): raise TasmanianInputError("iOutputs", "ERROR: outputs should be a non-negative integer") if (iDepth < 0): raise TasmanianInputError("iDepth", "ERROR: depth should be a non-negative integer") if (iOrder < -1): raise TasmanianInputError("iOrder", "ERROR: order should be a non-negative integer") if (sRule not in lsTsgLocalRules): raise TasmanianInputError("sRule", "ERROR: invalid local polynomial rule, see TasmanianSG.lsTsgLocalRules for list of accepted sequence rules") pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgMakeLocalPolynomialGrid(self.pGrid, iDimension, iOutputs, iDepth, iOrder, bytes(sRule, encoding='utf8'), pLevelLimits) def makeWaveletGrid(self, iDimension, iOutputs, iDepth, iOrder=1, liLevelLimits=[]): ''' creates a new sparse grid using a wavelet rule discards any existing grid held by this class iDimension: int (positive) the number of inputs iOutputs: int (non-negative) the number of outputs iDepth: int (non-negative) controls the density of the grid, i.e., the number of levels to use iOrder: int (must be 1 or 3) only wavelets of order 1 and 3 are implemented ''' if (iDimension <= 0): raise TasmanianInputError("iDimension", "ERROR: dimension should be a positive integer") if (iOutputs < 0): raise TasmanianInputError("iOutputs", "ERROR: outputs should be a non-negative integer") if (iDepth < 0): raise TasmanianInputError("iDepth", "ERROR: depth should be a non-negative integer") if (iOrder not in [1, 3]): raise TasmanianInputError("iOrder", "ERROR: order should be either 1 or 3 (only linear and cubic wavelets are available)") pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgMakeWaveletGrid(self.pGrid, iDimension, iOutputs, iDepth, iOrder, pLevelLimits) def makeFourierGrid(self, iDimension, iOutputs, iDepth, sType, liAnisotropicWeights=[], liLevelLimits=[]): ''' creates a new sparse grid using a Fourier rule discards any existing grid held by this class iDimension: int (positive) the number of inputs iOutputs: int (non-negative) the number of outputs iDepth: int (non-negative) controls the density of the grid, i.e., the offset for the tensor selection, the meaning of iDepth depends on sType sType: string identifying the tensor selection strategy 'level' 'curved' 'hyperbolic' 'tensor' 'iptotal' 'ipcurved' 'iphyperbolic' 'iptensor' 'qptotal' 'qpcurved' 'qphyperbolic' 'qptensor' liAnisotropicWeights: list or numpy.ndarray of weights length must be iDimension or 2*iDimension the first iDimension weights must be positive see the manual for details ''' if (iDimension <= 0): raise TasmanianInputError("iDimension", "ERROR: dimension should be a positive integer") if (iOutputs < 0): raise TasmanianInputError("iOutputs", "ERROR: outputs should be a non-negative integer") if (iDepth < 0): raise TasmanianInputError("iDepth", "ERROR: depth should be a non-negative integer") if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see TasmanianSG.lsTsgGlobalTypes for list of accepted types") pAnisoWeights = None if (len(liAnisotropicWeights) > 0): if (sType in lsTsgCurvedTypes): iNumWeights = 2*iDimension else: iNumWeights = iDimension if (len(liAnisotropicWeights) != iNumWeights): raise TasmanianInputError("liAnisotropicWeights", "ERROR: wrong number of liAnisotropicWeights, sType '{0:s}' needs {1:1d} weights but len(liAnisotropicWeights) == {2:1d}".format(sType, iNumWeights, len(liAnisotropicWeights))) else: pAnisoWeights = (c_int*iNumWeights)() for iI in range(iNumWeights): pAnisoWeights[iI] = liAnisotropicWeights[iI] pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgMakeFourierGrid(self.pGrid, iDimension, iOutputs, iDepth, bytes(sType, encoding='utf8'), pAnisoWeights, pLevelLimits) def makeGlobalGridCustom(self, iDimension, iOutputs, iDepth, sType, pCustomTabulated, liAnisotropicWeights=[], liLevelLimits=[]): ''' Creates a new sparse grid using a CustomTabulated object. Discards any existing grid held by this class. Uses the same inputs as in makeGlobalGrid(), but with an additional input named pCustomTabulated. This new input should be a Python CustomTabulated object, which will be used to populate the weights and nodes of the output grid. See the manual for more details. ''' if not hasattr(pCustomTabulated, "CustomTabulatedObject"): raise TasmanianInputError("pCustomTabulated", "ERROR: pCustomTabulated must be an instance of CustomTabulated") self.__testMakeGlobalGrid(iDimension, iOutputs, iDepth, sType, liAnisotropicWeights, liLevelLimits) pAnisoWeights = None if (len(liAnisotropicWeights) > 0): iNumWeights = 2*iDimension if sType in lsTsgCurvedTypes else iDimension pAnisoWeights = (c_int*iNumWeights)() for iI in range(iNumWeights): pAnisoWeights[iI] = liAnisotropicWeights[iI] pLevelLimits = None if (len(liLevelLimits) > 0): pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgMakeGridFromCustomTabulated(c_void_p(self.pGrid), c_int(iDimension), c_int(iOutputs), c_int(iDepth), bytes(sType, encoding='utf8'), c_void_p(pCustomTabulated.pCustomTabulated), pAnisoWeights, pLevelLimits) def copyGrid(self, pGrid, iOutputsBegin = 0, iOutputsEnd = -1): ''' accepts an instance of TasmanianSparseGrid class and creates a hard copy of the class and all included data original class is not modified pGrid: instance of TasmanianSparseGrid class the source for the copy iOutputsBegin: integer indicating the first output to copy iOutputsEnd: integer one bigger than the last output to copy if set to -1, all outputs from iOutputsBegin to the end will be copied Examples: grid.copyGrid(other, 0, -1) # copy all outputs (default) grid.copyGrid(other, 0, other.getNumOutputs()) # also copy all grid.copyGrid(other, 0, 3) # copy outputs 0, 1, and 2 grid.copyGrid(other, 1, 4) # copy outputs 1, 2, and 3 ''' if (not isinstance(pGrid, TasmanianSparseGrid)): raise TasmanianInputError("pGrid", "ERROR: pGrid must be an instance of TasmanianSparseGrid") pLibTSG.tsgCopySubGrid(self.pGrid, pGrid.pGrid, iOutputsBegin, iOutputsEnd) def updateGlobalGrid(self, iDepth, sType, liAnisotropicWeights=[], liLevelLimits=[]): ''' adds the points defined by depth, type and anisotropy to the existing grid basically, the same as calling makeGlobalGrid with sRule, fAlpha and fBeta of this grid and the new iDepth, sType and liAnisotropicWeights then adding the resulting points to the current grid inputs: see help(TasmanianSG.TasmanianSparseGrid.makeGlobalGrid) ''' if (not self.isGlobal()): raise TasmanianInputError("updateGlobalGrid", "ERROR: calling updateGlobalGrid for a grid that is not global") if (iDepth < 0): raise TasmanianInputError("iDepth", "ERROR: depth should be a non-negative integer") if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see TasmanianSG.lsTsgGlobalTypes for list of accepted types") iDimension = self.getNumDimensions() pAnisoWeights = None if (len(liAnisotropicWeights) > 0): if (sType in lsTsgCurvedTypes): iNumWeights = 2*iDimension else: iNumWeights = iDimension if (len(liAnisotropicWeights) != iNumWeights): raise TasmanianInputError("liAnisotropicWeights", "ERROR: wrong number of liAnisotropicWeights, sType '{0:s}' needs {1:1d} weights but len(liAnisotropicWeights) == {2:1d}".format(sType, iNumWeights, len(liAnisotropicWeights))) else: pAnisoWeights = (c_int*iNumWeights)() for iI in range(iNumWeights): pAnisoWeights[iI] = liAnisotropicWeights[iI] pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgUpdateGlobalGrid(self.pGrid, iDepth, bytes(sType, encoding='utf8'), pAnisoWeights, pLevelLimits) def updateSequenceGrid(self, iDepth, sType, liAnisotropicWeights=[], liLevelLimits=[]): ''' adds the points defined by depth, type and anisotropy to the existing grid basically, the same as calling makeSequenceGrid() with sRule, of this grid and the new iDepth, sType and liAnisotropicWeights then adding the resulting points to the current grid inputs: see help(Tasmanian.SparseGrid.makeGlobalGrid) ''' if (not self.isSequence()): raise TasmanianInputError("updateSequenceGrid", "ERROR: calling updateSequenceGrid for a grid that is not a sequence grid") if (iDepth < 0): raise TasmanianInputError("iDepth", "ERROR: depth should be a non-negative integer") if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see TasmanianSG.lsTsgGlobalTypes for list of accepted types") iDimension = self.getNumDimensions() pAnisoWeights = None if (len(liAnisotropicWeights) > 0): if (sType in lsTsgCurvedTypes): iNumWeights = 2*iDimension else: iNumWeights = iDimension if (len(liAnisotropicWeights) != iNumWeights): raise TasmanianInputError("liAnisotropicWeights", "ERROR: wrong number of liAnisotropicWeights, sType '{0:s}' needs {1:1d} weights but len(liAnisotropicWeights) == {2:1d}".format(sType, iNumWeights, len(liAnisotropicWeights))) else: pAnisoWeights = (c_int*iNumWeights)() for iI in range(iNumWeights): pAnisoWeights[iI] = liAnisotropicWeights[iI] pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgUpdateSequenceGrid(self.pGrid, iDepth, bytes(sType, encoding='utf8'), pAnisoWeights, pLevelLimits) def updateFourierGrid(self, iDepth, sType, liAnisotropicWeights=[], liLevelLimits=[]): ''' adds the points defined by depth, type and anisotropy to the existing grid basically, the same as calling makeFourierGrid() with sRule, of this grid and the new iDepth, sType and liAnisotropicWeights then adding the resulting points to the current grid inputs: see help(Tasmanian.SparseGrid.makeGlobalGrid) ''' if (not self.isFourier()): raise TasmanianInputError("updateFourierGrid", "ERROR: calling updateFourierGrid for a grid that is not a Fourier grid") if (iDepth < 0): raise TasmanianInputError("iDepth", "ERROR: depth should be a non-negative integer") if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see Tasmanian.TasmanianSG.lsTsgGlobalTypes for list of accepted types") iDimension = self.getNumDimensions() pAnisoWeights = None if (len(liAnisotropicWeights) > 0): if (sType in lsTsgCurvedTypes): iNumWeights = 2*iDimension else: iNumWeights = iDimension if (len(liAnisotropicWeights) != iNumWeights): raise TasmanianInputError("liAnisotropicWeights", "ERROR: wrong number of liAnisotropicWeights, sType '{0:s}' needs {1:1d} weights but len(liAnisotropicWeights) == {2:1d}".format(sType, iNumWeights, len(liAnisotropicWeights))) else: pAnisoWeights = (c_int*iNumWeights)() for iI in range(iNumWeights): pAnisoWeights[iI] = liAnisotropicWeights[iI] pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgUpdateFourierGrid(self.pGrid, iDepth, bytes(sType, encoding='utf8'), pAnisoWeights, pLevelLimits) def getAlpha(self): ''' returns the value of fAlpha in the call to makeGlobalGrid if makeGlobalGrid has not been called, returns 0.0 ''' return pLibTSG.tsgGetAlpha(self.pGrid) def getBeta(self): ''' returns the value of fBeta in the call to makeGlobalGrid if makeGlobalGrid has not been called, returns 0.0 ''' return pLibTSG.tsgGetBeta(self.pGrid) def getOrder(self): ''' returns the value of iOrder in the call to makeLocalPolynomialGrid or makeWaveletGrid if makeLocalPolynomialGrid and makeWaveletGrid have not been called, returns -1 ''' return pLibTSG.tsgGetOrder(self.pGrid) def getNumDimensions(self): ''' returns the value of iDimension in the make***Grid command if no grid has been made, it returns 0 ''' return pLibTSG.tsgGetNumDimensions(self.pGrid) def getNumOutputs(self): ''' returns the value of iOutputs in the make***Grid command if no grid has been made, it returns 0 ''' return pLibTSG.tsgGetNumOutputs(self.pGrid) def getRule(self): ''' returns the value of sRule in the make***Grid command if makeWaveletGrid is used, returns "wavelet" if no grid has been made, it returns "unknown" ''' pName = create_string_buffer(128); iNumChars = np.array([0], np.int32) pLibTSG.tsgCopyRuleChars(self.pGrid, 128, pName, np.ctypeslib.as_ctypes(iNumChars)) return self.stringBufferToString(pName, iNumChars[0]) def getCustomRuleDescription(self): ''' returns the description provided in the custom rule file if not using a custom grid, returns "" ''' return str(pLibTSG.tsgGetCustomRuleDescription(self.pGrid), encoding='utf8') if "custom-tabulated" in self.getRule() else "" def getNumLoaded(self): ''' returns the number of points loaded in the existing interpolant ''' return pLibTSG.tsgGetNumLoaded(self.pGrid) def getNumNeeded(self): ''' returns the number of points needed to form the interpolant or form the next interpolant following a refinement ''' return pLibTSG.tsgGetNumNeeded(self.pGrid) def getNumPoints(self): ''' if points have been loaded, returns the same as getNumLoaded() otherwise, returns the same as getNumNeeded() ''' return pLibTSG.tsgGetNumPoints(self.pGrid) def getLoadedPoints(self): ''' returns the points loaded in the existing interpolant output: a 2-D numpy.ndarray of size getNumLoaded() X iDimension reach row corresponds to one point if (getNumLoaded() == 0): returns numpy.empty([0,0]) ''' iNumDims = self.getNumDimensions() iNumPoints = self.getNumLoaded() if (iNumPoints == 0): return np.empty([0, 0], np.float64) aPoints = np.empty([iNumPoints * iNumDims], np.float64) pLibTSG.tsgGetLoadedPointsStatic(self.pGrid, np.ctypeslib.as_ctypes(aPoints)) return aPoints.reshape([iNumPoints, iNumDims]) def getNeededPoints(self): ''' returns the points needed to form the interpolant or the next level of refinement following a set***Refinement() call output: 2-D numpy.ndarray of size getNumNeeded() X iDimension reach row corresponds to one point if (getNumNeeded() == 0): returns numpy.empty([0,0]) ''' iNumDims = self.getNumDimensions() iNumPoints = self.getNumNeeded() if (iNumPoints == 0): return np.empty([0, 0], np.float64) aPoints = np.empty([iNumPoints * iNumDims], np.float64) pLibTSG.tsgGetNeededPointsStatic(self.pGrid, np.ctypeslib.as_ctypes(aPoints)) return aPoints.reshape([iNumPoints, iNumDims]) def getPoints(self): ''' if points have been loaded, gives the same as getLoadedPoints() otherwise, returns the same as getNeededPoints() ''' iNumDims = self.getNumDimensions() iNumPoints = self.getNumPoints() if (iNumPoints == 0): return np.empty([0, 0], np.float64) aPoints = np.empty([iNumPoints * iNumDims], np.float64) pLibTSG.tsgGetPointsStatic(self.pGrid, np.ctypeslib.as_ctypes(aPoints)) return aPoints.reshape([iNumPoints, iNumDims]) def getQuadratureWeights(self): ''' returns the quadrature weights associated with the points in getPoints() output: a 1-D numpy.ndarray of length getNumPoints() the order of the weights matches the order in getPoints() ''' iNumPoints = self.getNumPoints() if (iNumPoints == 0): return np.empty([0], np.float64) aWeights = np.empty([iNumPoints], np.float64) pLibTSG.tsgGetQuadratureWeightsStatic(self.pGrid, np.ctypeslib.as_ctypes(aWeights)) return aWeights def getInterpolationWeights(self, lfX): ''' returns the interpolation weights associated with the points in getPoints() lfX: a 1-D numpy.ndarray with length iDimensions the entries indicate the points for evaluating the weights output: a 1-D numpy.ndarray of length getNumPoints() the order of the weights matches the order in getPoints() ''' iNumX = len(lfX) if (iNumX != self.getNumDimensions()): raise TasmanianInputError("lfX", "ERROR: len(lfX) should equal {0:1d} instead it equals {1:1d}".format(self.getNumDimensions(), iNumX)) iNumPoints = self.getNumPoints() if (iNumPoints == 0): return np.empty([0], np.float64) aWeights = np.empty([iNumPoints], np.float64) pLibTSG.tsgGetInterpolationWeightsStatic(self.pGrid, np.ctypeslib.as_ctypes(lfX), np.ctypeslib.as_ctypes(aWeights)) return aWeights def getInterpolationWeightsBatch(self, llfX): ''' returns the interpolation weights associated with the points in getPoints() finds multiple weights with a single library call uses OpenMP if enabled in libtasmaniansparsegrids.so llfX: a 2-D numpy.ndarray with second dimension iDimensions each row in the array is a single requested point output: a 2-D numpy.ndarray with dimensions llfX.shape[0] X getNumPoints() each row corresponds to the weight for one row of llfX ''' if (len(llfX.shape) != 2): raise TasmanianInputError("llfX", "ERROR: llfX should be a 2-D numpy.ndarray instread it has dimension {0:1d}".format(len(llfX.shape))) iNumX = llfX.shape[0] if (iNumX == 0): return np.empty([0, self.getNumPoints()], np.float64) iNumDim = llfX.shape[1] if (iNumDim != self.getNumDimensions()): raise TasmanianInputError("llfX", "ERROR: llfX.shape[1] should equal {0:1d} instead it equals {1:1d}".format(self.getNumDimensions(), iNumDim)) iNumPoints = self.getNumPoints() if (iNumPoints == 0): return np.empty([0, 0], np.float64) aWeights = np.empty([iNumX, iNumPoints], np.float64) pLibTSG.tsgBatchGetInterpolationWeightsStatic(self.pGrid, np.ctypeslib.as_ctypes(llfX.reshape([iNumX * iNumDim])), iNumX, np.ctypeslib.as_ctypes(aWeights.reshape([iNumX * iNumPoints]))) return aWeights def loadNeededValues(self, llfVals): ''' loads the values of the target function at the needed points if there are no needed points, this reset the currently loaded values llfVals: a 2-D numpy.ndarray with dimensions getNumNeeded() X iOutputs each row corresponds to the values of the outputs at the corresponding needed point. The order and leading dimension must match the points obtained form getNeededPoints() ''' if (len(llfVals.shape) != 2): raise TasmanianInputError("llfVals", "ERROR: llfVals should be a 2-D numpy.ndarray, instead it has {0:1d} dimensions".format(len(llfVals.shape))) if (self.getNumNeeded() == 0): if (llfVals.shape[0] != self.getNumLoaded()): raise TasmanianInputError("llfVals", "ERROR: leading dimension of llfVals is {0:1d} but the number of current points is {1:1d}".format(llfVals.shape[0], self.getNumLoaded())) elif (llfVals.shape[0] != self.getNumNeeded()): raise TasmanianInputError("llfVals", "ERROR: leading dimension of llfVals is {0:1d} but the number of needed points is {1:1d}".format(llfVals.shape[0], self.getNumNeeded())) if (llfVals.shape[1] != self.getNumOutputs()): raise TasmanianInputError("llfVals", "ERROR: second dimension of llfVals is {0:1d} but the number of outputs is set to {1:1d}".format(llfVals.shape[1], self.getNumOutputs())) iNumPoints = llfVals.shape[0] iNumDims = llfVals.shape[1] pLibTSG.tsgLoadNeededValues(self.pGrid, np.ctypeslib.as_ctypes(llfVals.reshape([iNumPoints * iNumDims]))) def loadNeededPoints(self, llfVals): ''' Alias of loadNeededValues(). ''' self.loadNeededValues(llfVals) def getLoadedValues(self): ''' Returns the model values as given to Tasmanian by the loadNeededPoints() method. The ordering will match the current internal ordering, e.g., mixing the different model values from different refinement iterations. Returns a two dimensional numpy.ndarray with size getNumPoints() by getNumOutputs() ''' iNumPoints = self.getNumPoints() iNumOutputs = self.getNumOutputs() if (iNumPoints == 0 or iNumOutputs == 0): return np.empty([0, 0], np.float64) aVals = np.empty((iNumPoints * iNumOutputs,), np.float64) pLibTSG.tsgGetLoadedValuesStatic(self.pGrid, np.ctypeslib.as_ctypes(aVals)) return aVals.reshape((iNumPoints, iNumOutputs)) def evaluateThreadSafe(self, lfX): ''' evaluates the intepolant at a single points of interest and returns the result This is the thread safe version, but it does not use acceleration of any type this should be called after the grid has been created and after values have been loaded lfX: a 1-D numpy.ndarray with length iDimensions the entries indicate the points for evaluating the weights output: returns a 1-D numpy.ndarray of length iOutputs the values of the interpolant at lfX ''' if (self.getNumLoaded() == 0): raise TasmanianInputError("evaluateThreadSafe", "ERROR: cannot call evaluate for a grid before any points are loaded, i.e., call loadNeededPoints first!") if (len(lfX.shape) != 1): raise TasmanianInputError("lfX", "ERROR: lfX should be 1D numpy array") iNumX = lfX.shape[0] if (iNumX != self.getNumDimensions()): raise TasmanianInputError("lfX", "ERROR: lfX should have lenth {0:1d} instead it has length {1:1d}".format(self.getNumDimensions(),iNumX)) iNumOutputs = self.getNumOutputs() aY = np.empty([iNumOutputs], np.float64) pLibTSG.tsgEvaluate(self.pGrid, np.ctypeslib.as_ctypes(lfX), np.ctypeslib.as_ctypes(aY)) return aY def evaluate(self, lfX): ''' evaluates the intepolant at a single points of interest and returns the result This is the accelerated version using the selected acceleration type, but it is potentially not thread safe this should be called after the grid has been created and after values have been loaded lfX: a 1-D numpy.ndarray with length iDimensions the entries indicate the points for evaluating the weights output: returns a 1-D numpy.ndarray of length iOutputs the values of the interpolant at lfX ''' if (self.getNumLoaded() == 0): raise TasmanianInputError("evaluate", "ERROR: cannot call evaluate for a grid before any points are loaded, i.e., call loadNeededPoints first!") if (len(lfX.shape) != 1): raise TasmanianInputError("lfX", "ERROR: lfX should be 1D numpy array") iNumX = lfX.shape[0] if (iNumX != self.getNumDimensions()): raise TasmanianInputError("lfX", "ERROR: lfX should have lenth {0:1d} instead it has length {1:1d}".format(self.getNumDimensions(),iNumX)) iNumOutputs = self.getNumOutputs() aY = np.empty([iNumOutputs], np.float64) pLibTSG.tsgEvaluateFast(self.pGrid, np.ctypeslib.as_ctypes(lfX), np.ctypeslib.as_ctypes(aY)) return aY def evaluateBatch(self, llfX): ''' evaluates the intepolant at the points of interest and returns the result this should be called after the grid has been created and after values have been loaded llfX: a 2-D numpy.ndarray with second dimension equal to iDimensions each row in the array is a single requested point output: a 2-D numpy.ndarray with dimensions llfX.shape[0] X iOutputs each row corresponds to the value of the interpolant for one row of llfX ''' if (self.getNumLoaded() == 0): raise TasmanianInputError("evaluateBatch", "ERROR: cannot call evaluateBatch for a grid before any points are loaded, i.e., call loadNeededPoints first!") if (len(llfX.shape) != 2): raise TasmanianInputError("llfX", "ERROR: llfX should be a 2-D numpy.ndarray instread it has dimension {0:1d}".format(len(llfX.shape))) iNumX = llfX.shape[0] if (iNumX == 0): return np.empty([0, self.getNumOutputs()], np.float64) iNumDim = llfX.shape[1] if (iNumDim != self.getNumDimensions()): raise TasmanianInputError("llfX", "ERROR: llfX.shape[1] should equal {0:1d} instead it equals {1:1d}".format(self.getNumDimensions(), iNumDim)) iNumOutputs = self.getNumOutputs() aY = np.empty([iNumX, iNumOutputs], np.float64) # np.ctypeslib.as_ctypes(llfX.reshape([iNumX*iNumDim,])) messes up, the first 4 entries randomly get set to machine eps (10^-310) and 0 lfX = llfX.reshape([iNumX*iNumDim,]) pLibTSG.tsgEvaluateBatch(self.pGrid, np.ctypeslib.as_ctypes(lfX), iNumX, np.ctypeslib.as_ctypes(aY.reshape([iNumX*iNumOutputs,]))) return aY def integrate(self): ''' returns the integral of the interpolant output: returns a 1-D numpy.ndarray of length iOutputs the integral of the interpolant ''' if (self.getNumLoaded() == 0): raise TasmanianInputError("integrate", "ERROR: cannot call integrate for a grid before any points are loaded, i.e., call loadNeededPoints first!") iNumOutputs = self.getNumOutputs() aQ = np.empty([iNumOutputs], np.float64) pLibTSG.tsgIntegrate(self.pGrid, np.ctypeslib.as_ctypes(aQ)) return aQ def differentiate(self, lfX): ''' returns the derivative (Jacobian or gradient vector) of the interpolant lfX: a 1-D numpy.ndarray with length iNumDimensions which is the evaluation point output: if iNumOutputs == 1, returns a 1-D numpy.ndarray of length iNumDimensions; if iNumOutputs >= 2, returns a 2-D numpy.ndarray of dimension [iNumOutputs, iNumDimensions] ''' if (self.getNumLoaded() == 0): raise TasmanianInputError("differentiate", "ERROR: cannot call differentiate for a grid before any points are loaded, i.e., call loadNeededPoints first!") iNumOutputs = self.getNumOutputs() iNumDimensions = self.getNumDimensions() aDx = np.empty([iNumDimensions * iNumOutputs], np.float64) pLibTSG.tsgDifferentiate(self.pGrid, np.ctypeslib.as_ctypes(lfX), np.ctypeslib.as_ctypes(aDx)) return np.squeeze(np.resize(aDx, [iNumOutputs, iNumDimensions])) def isGlobal(self): ''' returns True if using a global grid ''' return (pLibTSG.tsgIsGlobal(self.pGrid) != 0) def isSequence(self): ''' returns True if using a sequence grid ''' return (pLibTSG.tsgIsSequence(self.pGrid) != 0) def isLocalPolynomial(self): ''' returns True if using a local polynomial grid ''' return (pLibTSG.tsgIsLocalPolynomial(self.pGrid) != 0) def isWavelet(self): ''' returns True if using a local wavelet grid ''' return (pLibTSG.tsgIsWavelet(self.pGrid) != 0) def isFourier(self): ''' returns True if using a Fourier grid ''' return (pLibTSG.tsgIsFourier(self.pGrid) != 0) def setDomainTransform(self, llfTransform): ''' sets the lower and upper bound for each dimension Note: gauss-laguerre and gauss-hermite rules are defined on unbounded domain, in which case this sets the shift and scale parameters, consult the manual llfTransform: a 2-D numpy.ndarray of size iDimension X 2 transform specifies the lower and upper bound of the domain in each direction. For gauss-laguerre and gauss-hermite grids, the transform gives the a and b parameters of the weights exp(-b (x - a)) exp(-b (x - a)^2) ''' lShape = llfTransform.shape if (len(lShape) != 2): raise TasmanianInputError("llfTransform", "ERROR: llfTransform should be a 2-D numpy.ndarray") if (lShape[0] != self.getNumDimensions()): raise TasmanianInputError("llfTransform", "ERROR: the first dimension of llfTransform is {0:1d} and it should match iDimension: {1:1d}".format(lShape[0], self.getNumDimensions())) if (lShape[1] != 2): raise TasmanianInputError("llfTransform", "ERROR: the second dimension of llfTransform is {0:1d} and it should be 2".format(lShape[1])) iNumDimensions = llfTransform.shape[0] # NOTE: copy is done to convert 2-D ndarray to two 1-D arrays pA = (c_double*iNumDimensions)() pB = (c_double*iNumDimensions)() for iI in range(iNumDimensions): pA[iI] = llfTransform[iI][0] pB[iI] = llfTransform[iI][1] pLibTSG.tsgSetDomainTransform(self.pGrid, pA, pB) def isSetDomainTransfrom(self): ''' returns True if the grid is defined for non-canonical domain returns False if using a canonical domain ''' return (pLibTSG.tsgIsSetDomainTransfrom(self.pGrid) != 0) def clearDomainTransform(self): ''' resets the domain to canonical loaded values will be kept, however, the values now correspond to canonical points and may be invalid for your application ''' pLibTSG.tsgClearDomainTransform(self.pGrid) def getDomainTransform(self): ''' returns llfTransform from the call to setDomainTransform() if setDomainTransform() has not been called or if the transformed has been cleared by clearDomainTransform(), then this returns an empty matrix ''' if (not self.isSetDomainTransfrom()): return np.empty([0,2], np.float64) iNumDimensions = self.getNumDimensions() pA = (c_double*iNumDimensions)() pB = (c_double*iNumDimensions)() pLibTSG.tsgGetDomainTransform(self.pGrid, pA, pB) llfTransform = np.empty([iNumDimensions, 2], np.float64) for iI in range(iNumDimensions): llfTransform[iI][0] = pA[iI] llfTransform[iI][1] = pB[iI] return llfTransform def setConformalTransformASIN(self, liTruncation): ''' sets conformal domain transform based on truncated Maclaurin series of arcsin() liTruncation: 1-D numpy.ndarray of non-negative integers indicating the truncation order in each direction 0 indicates no transform applied to this direction ''' lShape = liTruncation.shape if (len(lShape) != 1): raise TasmanianInputError("liTruncation", "ERROR: liTruncation should be a 1-D numpy.ndarray") if (lShape[0] != self.getNumDimensions()): raise TasmanianInputError("liTruncation", "ERROR: the length of liTruncation is {0:1d} and it should match iDimension: {1:1d}".format(lShape[0], self.getNumDimensions())) iNumDimensions = lShape[0] pTruncation = (c_int*iNumDimensions)() for iI in range(iNumDimensions): pTruncation[iI] = liTruncation[iI] # this converts Python longs to c_int pLibTSG.tsgSetConformalTransformASIN(self.pGrid, pTruncation) def isSetConformalTransformASIN(self): ''' returns True if conformal transform is set returns False otherwise see: setConformalTransformASIN() ''' return (pLibTSG.tsgIsSetConformalTransformASIN(self.pGrid) != 0) def clearConformalTransform(self): ''' resets the conformal domain transform loaded values will be kept, however, the values now correspond to canonical points and may be invalid for your application ''' pLibTSG.tsgClearConformalTransform(self.pGrid) def getConformalTransformASIN(self): ''' returns liTruncation from the call to setConformalTransformASIN() if setConformalTransformASIN() has not been called or if the transformed has been cleared by clearConformalTransform(), then this returns an empty matrix ''' if (not self.isSetConformalTransformASIN()): return np.empty([0,], int) iNumDimensions = self.getNumDimensions() pTruncation = (c_int*iNumDimensions)() pLibTSG.tsgGetConformalTransformASIN(self.pGrid, pTruncation) liTruncation = np.empty([iNumDimensions,], int) for iI in range(iNumDimensions): liTruncation[iI] = pTruncation[iI] # convert c_int to python long return liTruncation def clearLevelLimits(self): ''' clears the limits set by the last make***Grid or refine command if no limits are set, this has no effect ''' pLibTSG.tsgClearLevelLimits(self.pGrid) def getLevelLimits(self): ''' returns the limits set by the last call to make***Grid or refine returns a vector of integers corresponding to the limits for each direction, -1 indicates no limit ''' iNumDimensions = self.getNumDimensions() pTruncation = (c_int*iNumDimensions)() pLibTSG.tsgGetLevelLimits(self.pGrid, pTruncation) liLimits = np.empty([iNumDimensions,], int) for iI in range(iNumDimensions): liLimits[iI] = pTruncation[iI] # convert c_int to python long return liLimits def setAnisotropicRefinement(self, sType, iMinGrowth, iOutput, liLevelLimits = []): ''' estimates anisotropic coefficients from the current set of loaded points and updates the grid with the best points according to the estimate sType: string identifying the estimate to use (see the Manual) recommended: 'iptotal' 'ipcurved' iMinGrowth: int (positive) minimum number of new points to include in the new grid iOutput: int (indicates the output to use) selects which output to use for refinement sequence grids accept -1 to indicate all outputs ''' if (self.getNumOutputs() == 0): raise TasmanianInputError("setAnisotropicRefinement", "ERROR: cannot set refinement for grid with iOutput = 0") if (self.getNumLoaded() == 0): raise TasmanianInputError("setAnisotropicRefinement", "ERROR: cannot call setAnisotropicRefinement for a grid before any points are loaded, i.e., call loadNeededPoints first!") if (iMinGrowth <= 0): raise TasmanianInputError("iMinGrowth", "ERROR: the number of growth should be positive integer") if (iOutput == -1): if (not self.isSequence()): raise TasmanianInputError("iOutput", "ERROR: iOutput = -1 can be used only for sequence grids") if (iOutput < -1): raise TasmanianInputError("iOutput", "ERROR: iOutput should be -1 or a non-negative integer") if (iOutput >= self.getNumOutputs()): raise TasmanianInputError("iOutput", "ERROR: iOutput cannot exceed the index of the last output {0:1d}".format(self.getNumOutputs() - 1)) if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see TasmanianSG.lsTsgGlobalTypes for list of accepted types") pLevelLimits = None if (len(liLevelLimits) > 0): iDimension = self.getNumDimensions() if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] pLibTSG.tsgSetAnisotropicRefinement(self.pGrid, bytes(sType, encoding='utf8'), iMinGrowth, iOutput, pLevelLimits) def getAnisotropicRefinement(self, sType, iMinGrowth, iOutput, liLevelLimits = []): ''' Calls setAnistropicRefinement() on the inputs and then getNeededPoints(). ''' self.setAnisotropicRefinement(sType, iMinGrowth, iOutput, liLevelLimits=liLevelLimits) return self.getNeededPoints() def estimateAnisotropicCoefficients(self, sType, iOutput): ''' returns the estimate of the anisotropic coefficients from the current set of loaded points see the manual sType: string identifying the estimate to use (see the Manual) recommended: 'iptotal' 'ipcurved' iOutput: int (indicates the output to use) selects which output to use for refinement sequence grids accept -1 to indicate all outputs outputs: 1-D numpy.ndarray of length getNumDimensions() or 2*getNumDimensions() the first set of getNumDimensions() entries correspond to the xi coefficients the second set of getNumDimensions() entries correspond to the eta coefficients ''' if (self.getNumOutputs() == 0): raise TasmanianInputError("estimateAnisotropicCoefficients", "ERROR: cannot set refinement for grid with iOutput = 0") if (self.getNumLoaded() == 0): raise TasmanianInputError("estimateAnisotropicCoefficients", "ERROR: cannot call estimateAnisotropicCoefficients for a grid before any points are loaded, i.e., call loadNeededPoints first!") if (iOutput == -1): if (not self.isSequence()): raise TasmanianInputError("iOutput", "ERROR: iOutput = -1 can be used only for sequence grids") if (iOutput < -1): raise TasmanianInputError("iOutput", "ERROR: iOutput should be -1 or a non-negative integer") if (iOutput >= self.getNumOutputs()): raise TasmanianInputError("iOutput", "ERROR: iOutput cannot exceed the index of the last output {0:1d}".format(self.getNumOutputs() - 1)) if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see TasmanianSG.lsTsgGlobalTypes for list of accepted types") iNumCoeffs = self.getNumDimensions() if ("curved" in sType): iNumCoeffs = iNumCoeffs * 2 aCoeff = np.empty([iNumCoeffs], np.int32) pLibTSG.tsgEstimateAnisotropicCoefficientsStatic(self.pGrid, bytes(sType, encoding='utf8'), iOutput, np.ctypeslib.as_ctypes(aCoeff)) return aCoeff def setSurplusRefinement(self, fTolerance, iOutput, sCriteria = "", liLevelLimits = [], llfScaleCorrection = []): ''' using hierarchical surplusses as an error indicator, the surplus refinement adds points to the grid to improve accuracy when using sequence grids: this algorithm corresponds to the greedy Knapsack problem when using local polynomial or wavelet grids, this call corresponds to local spatial refinement fTolerance: float (non-negative) the relative error tolerance, i.e., we refine only for points associated with surplus that exceeds the tolerance iOutput: int (indicates the output to use) selects which output to use for refinement sequence and local polynomial grids accept -1 to indicate all outputs sCriteria: hierarchical and direction refinement strategy 'classic' 'parents' 'direction' 'fds' 'stable' applicable only for Local Polynomial and Wavelet grids llfScaleCorrection: 2-D numpy.ndarray of non-negative numbers Instead of comparing the normalized surpluses to the tolerance, the scaled surplus will be used. The correction allows to manually guide the refinement process. The surplus of the j-th output of the i-th point will be scaled by llfScaleCorrection[i][j]. llfScaleCorrection.shape[0] must be equal to getNumLoaded() If empty, the scale is assumed 1.0 llfScaleCorrection.shape[1] must be equal to the number of outputs used in the process, which is equal to getNumOutputs() for iOutput == -1, or 1 if iOutput > -1. ''' if (self.isGlobal()): if (self.getRule() not in lsTsgSequenceRules): raise TasmanianInputError("setSurplusRefinement", "ERROR: setSurplusRefinement cannot be used with global grids with non-sequence rule") if (self.getNumLoaded() == 0): raise TasmanianInputError("setSurplusRefinement", "ERROR: cannot call setSurplusRefinement for a grid before any points are loaded, i.e., call loadNeededPoints first!") if (fTolerance < 0.0): raise TasmanianInputError("fTolerance", "ERROR: fTolerance must be non-negative") iActiveOutputs = self.getNumOutputs() pScaleCorrection = None if (len(llfScaleCorrection) > 0): if (iOutput > -1): iActiveOutputs = 1 if (len(llfScaleCorrection.shape) != 2): raise TasmanianInputError("llfScaleCorrection", "ERROR: llfScaleCorrection must be a 2-D numpy.ndarray, instead it has {0:1d} dimensions".format(len(llfScaleCorrection.shape))) if (llfScaleCorrection.shape[0] != self.getNumLoaded()): raise TasmanianInputError("llfScaleCorrection", "ERROR: leading dimension of llfScaleCorrection is {0:1d} but the number of current points is {1:1d}".format(llfScaleCorrection.shape[0], self.getNumLoaded())) if (llfScaleCorrection.shape[1] != iActiveOutputs): raise TasmanianInputError("llfScaleCorrection", "ERROR: second dimension of llfScaleCorrection is {0:1d} but the refinement is set to use {1:1d}".format(llfScaleCorrection.shape[0], iActiveOutputs)) pScaleCorrection = np.ctypeslib.as_ctypes(llfScaleCorrection.reshape([self.getNumLoaded() * iActiveOutputs])) pLevelLimits = None if (len(liLevelLimits) > 0): iDimension = self.getNumDimensions() if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") pLevelLimits = (c_int*iDimension)() for iI in range(iDimension): pLevelLimits[iI] = liLevelLimits[iI] if (len(sCriteria) == 0): if (not self.isSequence() and not self.isGlobal()): raise TasmanianInputError("sCriteria", "ERROR: sCriteria must be specified") pLibTSG.tsgSetGlobalSurplusRefinement(self.pGrid, c_double(fTolerance), iOutput, pLevelLimits) else: if (self.isSequence()): raise TasmanianInputError("sCriteria", "ERROR: sCriteria cannot be used for sequence grids") if (not sCriteria in lsTsgRefineTypes): raise TasmanianInputError("sCriteria", "ERROR: invalid criteria, see TasmanianSG.lsTsgRefineTypes for the list of accepted types") pLibTSG.tsgSetLocalSurplusRefinement(self.pGrid, c_double(fTolerance), bytes(sCriteria, encoding='utf8'), iOutput, pLevelLimits, pScaleCorrection) def getSurplusRefinement(self, fTolerance, iOutput, sCriteria = "", liLevelLimits = [], llfScaleCorrection = []): ''' Calls setSurplusRefinement() on the inputs and then getNeededPoints(). ''' self.setSurplusRefinement(fTolerance, iOutput, sCriteria=sCriteria, liLevelLimits=liLevelLimits, llfScaleCorrection=llfScaleCorrection) return self.getNeededPoints() def clearRefinement(self): ''' clear the last call to set***Refinement, only works if called before the points are loaded, i.e., before loadNeededPoints() if getNumNeeded() == 0, this call will have no effect ''' pLibTSG.tsgClearRefinement(self.pGrid) def mergeRefinement(self): ''' combines the loaded and needed points into a single grid it also invalidates any currently loaded values, i.e., the grid cannot be used for internal integration or interpolation until loadNeededPoints() or setHierarchicalCoefficients() is called (even if those have been called before) if getNumNeeded() == 0, this call will have no effect ''' pLibTSG.tsgMergeRefinement(self.pGrid) def beginConstruction(self): ''' start dynamic construction procedure ''' pLibTSG.tsgBeginConstruction(self.pGrid) def isUsingConstruction(self): ''' check if using dynamic construction ''' return (pLibTSG.tsgIsUsingConstruction(self.pGrid) != 0) def getCandidateConstructionPoints(self, sType, liAnisotropicWeightsOrOutput, liLevelLimits = []): ''' returns the sorted points for the construction ''' if (not self.isUsingConstruction()): raise TasmanianInputError("getCandidateConstructionPoints", "ERROR: calling getCandidateConstructionPoints() before beginConstruction()") if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see TasmanianSG.lsTsgGlobalTypes for list of accepted types") iNumDims = self.getNumDimensions() pAnisoWeights = None iOutput = -1 if (isinstance(liAnisotropicWeightsOrOutput, int)): iOutput = liAnisotropicWeightsOrOutput elif (isinstance(liAnisotropicWeightsOrOutput, (list, np.ndarray))): if (len(liAnisotropicWeightsOrOutput) > 0): if (sType in lsTsgCurvedTypes): iNumWeights = 2*iNumDims else: iNumWeights = iNumDims if (len(liAnisotropicWeightsOrOutput) != iNumWeights): raise TasmanianInputError("liAnisotropicWeightsOrOutput", "ERROR: wrong number of liAnisotropicWeights, sType '{0:s}' needs {1:1d} weights but len(liAnisotropicWeights) == {2:1d}".format(sType, iNumWeights, len(liAnisotropicWeightsOrOutput))) else: aAWeights = np.array([liAnisotropicWeightsOrOutput[i] for i in range(iNumWeights)], np.int32) pAnisoWeights = np.ctypeslib.as_ctypes(aAWeights) else: raise TasmanianInputError("liAnisotropicWeightsOrOutput", "ERROR: liAnisotropicWeightsOrOutput should be either an integer or numpy.ndarray") pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iNumDims): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to the grid dimension") pLevelLimits = (c_int*iNumDims)() for iI in range(iNumDims): pLevelLimits[iI] = liLevelLimits[iI] pVector = pLibTSG.tsgGetCandidateConstructionPointsVoidPntr(self.pGrid, bytes(sType, encoding='utf8'), iOutput, pAnisoWeights, pLevelLimits) iNumPoints = pLibTSG.tsgGetCandidateConstructionPointsPythonGetNP(self.pGrid, pVector) if (iNumPoints == 0): pLibTSG.tsgGetCandidateConstructionPointsPythonDeleteVect(pVector) return np.empty([0, 0], np.float64) aPoints = np.empty([iNumPoints * iNumDims], np.float64) pLibTSG.tsgGetCandidateConstructionPointsPythonStatic(pVector, np.ctypeslib.as_ctypes(aPoints)) pLibTSG.tsgGetCandidateConstructionPointsPythonDeleteVect(pVector) return aPoints.reshape([iNumPoints, iNumDims]) def getCandidateConstructionPointsSurplus(self, fTolerance, sRefinementType, iOutput = -1, liLevelLimits = [], aScaleCorrection = []): ''' returns the sorted points for the construction ''' if (not self.isUsingConstruction()): raise TasmanianInputError("getCandidateConstructionPointsSurplus", "ERROR: calling getCandidateConstructionPointsSurplus() before beginConstruction()") iNumDims = self.getNumDimensions() if (not sRefinementType in lsTsgRefineTypes): raise TasmanianInputError("sRefinementType", "ERROR: calling getCandidateConstructionPointsSurplus() called with incorrect type, see TasmanianSG.lsTsgRefineTypes") pLevelLimits = None if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iNumDims): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to the grid dimension") pLevelLimits = (c_int*iNumDims)() for iI in range(iNumDims): pLevelLimits[iI] = liLevelLimits[iI] pScale = None if (len(aScaleCorrection) > 0): pScale = np.ctypeslib.as_ctypes(aScaleCorrection.reshape([np.prod(aScaleCorrection.shape),])) pVector = pLibTSG.tsgGetCandidateConstructionPointsSurplusVoidPntr(self.pGrid, c_double(fTolerance), bytes(sRefinementType, encoding='utf8'), iOutput, pLevelLimits, pScale) iNumPoints = pLibTSG.tsgGetCandidateConstructionPointsPythonGetNP(self.pGrid, pVector) if (iNumPoints == 0): pLibTSG.tsgGetCandidateConstructionPointsPythonDeleteVect(pVector) return np.empty([0, 0], np.float64) aPoints = np.empty([iNumPoints * iNumDims], np.float64) pLibTSG.tsgGetCandidateConstructionPointsPythonStatic(pVector, np.ctypeslib.as_ctypes(aPoints)) pLibTSG.tsgGetCandidateConstructionPointsPythonDeleteVect(pVector) return aPoints.reshape([iNumPoints, iNumDims]) def loadConstructedPoint(self, lfX, lfY): ''' load the currently computed point or points lfX: should be 1D (single point case) or 2D (multi-point case) numpy.ndarray 1D case: the lenght should be iDimensions indicating the computed point 2D case: lfX.shape[1] shold be iDimensions and lfX.shape[0] should be the number of computed points lfY: should be a 1D or 2D numpy.ndarray matching lfY 1D case: the length should be iOutputs indicated the corresponding model value 2D case: lfY.shape[1] should be iOutputs and lfY.shape[0] must match lfX.shape[0] if lfX or lfY are not numpy.ndarrays, an attempt would be made to cast them using numpy.array() funciton (e.g., lfX and lfY could be 1D lists or tuples). ''' if (not self.isUsingConstruction()): raise TasmanianInputError("loadConstructedPoint", "ERROR: calling loadConstructedPoint() before beginConstruction()") iNumDims = self.getNumDimensions() iNumOuts = self.getNumOutputs() if (not isinstance(lfX, np.ndarray)): lfX = np.array(lfX) if (not isinstance(lfY, np.ndarray)): lfY = np.array(lfY) if (len(lfX.shape) == 1): if (lfX.shape[0] != iNumDims): raise TasmanianInputError("lfX", "ERROR: lfX should be 1D numpy.ndarray with length equal to the grid dimension") if (len(lfY.shape) != 1 or lfY.shape[0] != iNumOuts): raise TasmanianInputError("lfY", "ERROR: lfY should be 1D numpy.ndarray with length equal to the model outputs") pLibTSG.tsgLoadConstructedPoint(self.pGrid, np.ctypeslib.as_ctypes(lfX), 1, np.ctypeslib.as_ctypes(lfY)) elif (len(lfX.shape) == 2): iNumX = lfX.shape[0] if (iNumX == 0): return if (len(lfY.shape) != 2): raise TasmanianInputError("lfY", "ERROR: if lfX is 2D array, then lfY should be 2D array as well") if (lfX.shape[1] != iNumDims): raise TasmanianInputError("lfX", "ERROR: lfX should be 2D numpy.ndarray with shape[1] equal to the grid dimension") if (lfY.shape[1] != iNumOuts): raise TasmanianInputError("lfY", "ERROR: lfY should be 2D numpy.ndarray with shape[1] equal to the model outputs") if (lfY.shape[0] != iNumX): raise TasmanianInputError("lfY", "ERROR: lfY should provide the same number of entries as lfX, i.e., shape[0] must match") pLibTSG.tsgLoadConstructedPoint(self.pGrid, np.ctypeslib.as_ctypes(lfX.reshape(iNumX * iNumDims)), iNumX, np.ctypeslib.as_ctypes(lfY.reshape(iNumX * iNumOuts))) else: raise TasmanianInputError("lfX", "ERROR: lfX should be 1D or 2D numpy.ndarray") def finishConstruction(self): ''' end the dynamic construction procedure ''' pLibTSG.tsgFinishConstruction(self.pGrid) def removePointsByHierarchicalCoefficient(self, fTolerance, iOutput = -1, aScaleCorrection = [], iNumKeep = -1): ''' removes any points in the grid with relative surplus that exceeds the tolerance or keeps the set number of points with largest surplus fTolerance: float (positive) the relative surplus tolerance, i.e., we keep only for points associated with surplus that exceeds the tolerance if iNumKeep is positive, then fTolerance is ignored iOutput: int (indicates the output to use) selects which output to consider accept -1 to indicate all outputs lfScaleCorrection: numpy array of doubles, either 1D or 2D if iOutputs = -1 and getNumOutputs() > 1, then using 2D array with shape getNumLoaded() X getNumOutputs() with one weight per hierarchical coefficient if iOutputs > -1, then using 1D array with one weight per point iNumKeep: int (positive or equal to -1) indicates the number of points to keep if set to -1 then fTolerance is used as a cutoff if positive then the given number of points will be kept ''' if (not self.isLocalPolynomial()): raise TasmanianInputError("removePointsByHierarchicalCoefficient", "ERROR: calling removePointsByHierarchicalCoefficient for a grid that isn't local polynomial") if (iNumKeep == -1 and fTolerance <= 0.0): raise TasmanianInputError("fTolerance", "ERROR: fTolerance must be a positive integer") if (iOutput < -1): raise TasmanianInputError("iOutput", "ERROR: iOutput should be -1 or a non-negative integer") if (iOutput >= self.getNumOutputs()): raise TasmanianInputError("iOutput", "ERROR: iOutput cannot exceed the index of the last output {0:1d}".format(self.getNumOutputs() - 1)) if (self.getNumLoaded() == 0): raise TasmanianInputError("removePointsByHierarchicalCoefficient", "ERROR: calling removePointsByHierarchicalCoefficient when no points are loades") if (iNumKeep == 0 or iNumKeep < -1 or iNumKeep > self.getNumLoaded()): raise TasmanianInputError("iNumKeep", "ERROR: iNumKeep should be either -1 or positive without exceeding the number of loaded points.") if (len(aScaleCorrection) > 0): lShape = aScaleCorrection.shape if (len(lShape) != 2): raise TasmanianInputError("aScaleCorrection", "ERROR: aScaleCorrection should be a 2D array") if (lShape[0] != self.getNumLoaded()): raise TasmanianInputError("aScaleCorrection", "ERROR: aScaleCorrection.shape[0] should match getNumLoaded()") if (iOutput == -1 and lShape[1] != self.getNumOutputs()): raise TasmanianInputError("aScaleCorrection", "ERROR: aScaleCorrection.shape[1] should match getNumOutputs()") if (iOutput != -1 and lShape[1] != 1): raise TasmanianInputError("aScaleCorrection", "ERROR: aScaleCorrection.shape[1] should be 1") if (len(aScaleCorrection) == 0): if (iNumKeep == -1): pLibTSG.tsgRemovePointsByHierarchicalCoefficient(self.pGrid, fTolerance, iOutput, None) else: pLibTSG.tsgRemovePointsByHierarchicalCoefficientHardCutoff(self.pGrid, iNumKeep, iOutput, None) else: lShape = aScaleCorrection.shape iNumWeights = lShape[0] if (iOutput == -1): iNumWeights *= lShape[1] if (iNumKeep == -1): pLibTSG.tsgRemovePointsByHierarchicalCoefficient(self.pGrid, fTolerance, iOutput, np.ctypeslib.as_ctypes(aScaleCorrection.reshape([iNumWeights,]))) else: pLibTSG.tsgRemovePointsByHierarchicalCoefficientHardCutoff(self.pGrid, iNumKeep, iOutput, np.ctypeslib.as_ctypes(aScaleCorrection.reshape([iNumWeights,]))) def getHierarchicalCoefficients(self): ''' For global grids, this just returns the values loaded using the call to loadNeededPoints(). In all other cases, this returns the list of hierarchical coefficients, i.e., surpluses. returns a 2-D numpy array getNumPoints() by getNumOutputs() ''' iNumOuts = self.getNumOutputs() if (iNumOuts == 0): return np.empty([0,0], np.float64) iNumPoints = self.getNumLoaded() if (iNumPoints == 0): return np.empty([0,iNumOuts], np.float64) if (not self.isFourier()): aSurp = np.empty([iNumOuts * iNumPoints], np.float64) pLibTSG.tsgGetHierarchicalCoefficientsStatic(self.pGrid, np.ctypeslib.as_ctypes(aSurp)) else: aSurp = np.empty([2 * iNumOuts * iNumPoints], np.float64) pLibTSG.tsgGetHierarchicalCoefficientsStatic(self.pGrid, np.ctypeslib.as_ctypes(aSurp)) aSurp = aSurp[:(iNumOuts * iNumPoints)] + 1j * aSurp[(iNumOuts * iNumPoints):] return aSurp.reshape([iNumPoints, iNumOuts]) def evaluateHierarchicalFunctions(self, llfX): ''' evaluates the hierarchical functions at a set of points in the domain and return a 2-D numpy.ndarray with the result llfX: a 2-D numpy.ndarray with llfX.shape[1] == iDimensions the entries indicate the points for evaluating the weights output: returns a 2-D numpy.ndarray of shape == [llfX.shape[0], getNumPoints()] the values of the basis functions at the points ''' if (len(llfX.shape) != 2): raise TasmanianInputError("llfX", "ERROR: calling evaluateHierarchicalFunctions llfX should be a 2-D numpy array") if (llfX.shape[1] != self.getNumDimensions()): raise TasmanianInputError("llfX", "ERROR: calling evaluateHierarchicalFunctions llfX.shape[1] is not equal to getNumDimensions()") iNumX = llfX.shape[0] # see evaluateBatch() lfX = llfX.reshape([llfX.shape[0] * llfX.shape[1]]) if not self.isFourier(): aResult = np.empty([iNumX * self.getNumPoints()], np.float64) pLibTSG.tsgEvaluateHierarchicalFunctions(self.pGrid, np.ctypeslib.as_ctypes(lfX), iNumX, np.ctypeslib.as_ctypes(aResult)) else: aResult = np.empty([2 * iNumX * self.getNumPoints()], np.float64) pLibTSG.tsgEvaluateHierarchicalFunctions(self.pGrid, np.ctypeslib.as_ctypes(lfX), iNumX, np.ctypeslib.as_ctypes(aResult)) aResult = aResult[0::2] + 1j * aResult[1::2] return aResult.reshape([iNumX, self.getNumPoints()]) def getHierarchicalSupport(self): ''' returns the support of the hierarchical basis in a 2-D numpy.ndarray - only local-polynomial and wavelet grids have restricted support - the support of all basis is restricted to the domain even if the support includes additional ares output: shape == [getNumPoints(), getNumDimensions()] the support entries correspond to the output of getPoints() if x represents a point in the domain and if abs( x[j] - getPoints()[i, j] ) > getSupport()[i, j] then the i-th entry in evaluateHierarchicalFunctions(x) corresponding to x is guaranteed to be zero ''' if (self.getNumPoints() == 0): return np.empty([0,0], np.float64) aResult = np.empty((self.getNumPoints() * self.getNumDimensions()), np.float64) pLibTSG.tsgGetHierarchicalSupportStatic(self.pGrid, np.ctypeslib.as_ctypes(aResult)) return aResult.reshape((self.getNumPoints(), self.getNumDimensions())) def evaluateSparseHierarchicalFunctions(self, llfX): ''' evaluates the hierarchical functions at a set of points in the domain. The distinction between this function and evaluateHierarchicalFunctions() lies in the type of the returned result, namely a sparse vs a dense matrix. The motivation for this function is that Local Polynomial and Wavelet grids usually result in sparse matrices llfX: a 2-D numpy.ndarray with llfX.shape[1] == iDimensions the entries indicate the points for evaluating output: returns a TasmanianSimpleSparseMatrix class which is a simple class with three fields: aPntr, aIndx, and aVals which are numpy.ndarray of types int32, int32, and float64 iNumRows and iNumCols are meta fields and have values iNumRows = llfX.shape[0] iNumCols = self.getNumPoints() The sparse matrix is compressed along the llfX.shape[0] dimension, i.e., using column compressed format ''' if (len(llfX.shape) != 2): raise TasmanianInputError("llfX", "ERROR: calling evaluateSparseHierarchicalFunctions(), llfX should be a 2-D numpy array") if (llfX.shape[1] != self.getNumDimensions()): raise TasmanianInputError("llfX", "ERROR: calling evaluateSparseHierarchicalFunctions(), llfX.shape[1] is not equal to getNumDimensions()") iNumX = llfX.shape[0] pMat = TasmanianSimpleSparseMatrix() iNumNZ = pLibTSG.tsgEvaluateSparseHierarchicalFunctionsGetNZ(self.pGrid, np.ctypeslib.as_ctypes(llfX.reshape([llfX.shape[0] * llfX.shape[1]])), iNumX) pMat.aPntr = np.empty([iNumX+1,], np.int32) pMat.aIndx = np.empty([iNumNZ,], np.int32) pMat.aVals = np.empty([iNumNZ if not self.isFourier() else 2 * iNumNZ,], np.float64) pMat.iNumRows = iNumX pMat.iNumCols = self.getNumPoints() # see evaluateBatch() lfX = llfX.reshape([llfX.shape[0] * llfX.shape[1]]) pLibTSG.tsgEvaluateSparseHierarchicalFunctionsStatic(self.pGrid, np.ctypeslib.as_ctypes(lfX), iNumX, np.ctypeslib.as_ctypes(pMat.aPntr), np.ctypeslib.as_ctypes(pMat.aIndx), np.ctypeslib.as_ctypes(pMat.aVals)) return pMat def setHierarchicalCoefficients(self, llfCoefficients): ''' Local polynomial, Wavelet, and Sequence grids construct approximation using hierarchical coefficients based on the loaded values. This function does the opposite, the hierarchical coefficients are loaded directly and the values are computed based on the coefficients. The coefficients can be computed, e.g., by solving least-squares or compressed sensing problem min || A c - f || where A is a matrix returned by evaluateHierarchicalFunctions() or evaluateSparseHierarchicalFunctions() for a set of points llfX; f are the values of the target function at the llfX points; and c is the vector with corresponding hierarchical coefficients. If there is a pending refinement, i.e., getNumLoaded() != 0 and getNumNeeded() != 0, then the refinement is discarded (since it was computed based on the old and now obsolete values) llfCoefficients: a 2-D numpy.ndarray with dimensions getNumPoints() X iOutputs each row corresponds to the values of the coefficients at the corresponding point. The order and leading dimension must match the points obtained form getPoints(), the same order as the second dimension of evaluateHierarchicalFunctions() ''' if (len(llfCoefficients.shape) != 2): raise TasmanianInputError("llfCoefficients", "ERROR: llfCoefficients should be a 2-D numpy.ndarray, instead it has {0:1d} dimensions".format(len(llfCoefficients.shape))) if (llfCoefficients.shape[0] != self.getNumPoints()): raise TasmanianInputError("llfCoefficients", "ERROR: leading dimension of llfCoefficients is {0:1d} but the number of current points is {1:1d}".format(llfCoefficients.shape[0], self.getNumNeeded())) if (llfCoefficients.shape[1] != self.getNumOutputs()): raise TasmanianInputError("llfCoefficients", "ERROR: second dimension of llfCoefficients is {0:1d} but the number of outputs is set to {1:1d}".format(llfCoefficients.shape[1], self.getNumOutputs())) if (self.isFourier() and (not np.iscomplexobj(llfCoefficients))): raise TasmanianInputError("llfCoefficients", "ERROR: using Fourier grid but llfCoefficients is not complex") iNumPoints = llfCoefficients.shape[0] iNumDims = llfCoefficients.shape[1] if self.isFourier(): llfCoefficientsTmp = np.vstack((np.real(llfCoefficients), np.imag(llfCoefficients))) llfCoefficients = llfCoefficientsTmp.reshape([2 * iNumPoints * iNumDims,]) else: llfCoefficients = llfCoefficients.reshape([iNumPoints * iNumDims,]) pLibTSG.tsgSetHierarchicalCoefficients(self.pGrid, np.ctypeslib.as_ctypes(llfCoefficients)) def integrateHierarchicalFunctions(self): ''' Computes the integrals of the hierarchical basis functions, i.e., the same functions computed by evaluateHierarchicalFunctions(). returns a one dimensional np.ndarray with size self.getNumPoints() ''' iNumPoints = self.getNumPoints() if (iNumPoints == 0): return np.empty([0,], np.float64) aIntegrals = np.zeros([iNumPoints,]) pLibTSG.tsgIntegrateHierarchicalFunctionsStatic(self.pGrid, np.ctypeslib.as_ctypes(aIntegrals)) return aIntegrals def getGlobalPolynomialSpace(self, bInterpolation): ''' returns a matrix corresponding to the polynomial space that is integrated or interpolated exactly by the current grid bInterpolation: boolean indicates whether to give the space associated with integration or interpolation output: is a 2-D numpy.ndarray of integers output.shape[0] indicates the cardinality of the space output.shape[1] is equal to iDimension each row corresponds to a multi-index associated with a polynomial in a hierarchical tensor basis, for example, monomials see the manual for details ''' iInterp = 0 if (bInterpolation): iInterp = 1 pNumIndexes = (c_int*1)() pIndexes = pLibTSG.tsgPythonGetGlobalPolynomialSpace(self.pGrid, iInterp, pNumIndexes) iNumDimensions = self.getNumDimensions() lliPolynomials = np.empty([pNumIndexes[0], iNumDimensions], int) for iI in range(pNumIndexes[0]): for iJ in range(iNumDimensions): lliPolynomials[iI][iJ] = pIndexes[iI*iNumDimensions + iJ] pLibTSG.tsgDeleteInts(pIndexes) return lliPolynomials def enableAcceleration(self, sAccelerationType, iGPUID = None): ''' Enables the use of accelerated backend libraries and extensions, such as BLAS and CUDA. Each acceleration type requires corresponding CMake compile options, otherwise the backend will fallback to the closest available options. sAccelerationType: string 'none' core fallback mode, relies on sequential implementation if compiled with Tasmanian_ENABLE_OPENMP this will use simple "omp parallel for" to take advantage of multiple cpu cores 'cpu-blas' uses BLAS level 2 and 3 functions for acceleration of batch evaluations requires Tasmanian_ENABLE_BLAS=ON this is the default mode, if available 'gpu-default' uses CUDA kernels, cuBlas, cuSparse and MAGMA libraries for accelerated matrix operations, e.g., cublasDgemm refer to TasGrid::TypeAcceleration for more details 'gpu_cublas' uses the Nvidia cuBlas and cuSparse libraries 'gpu-cuda' uses custom CUDA kernels in addition to the accelerated linear algebra libraries 'gpu-magma' uses the custom CUDA kernels and the MAGMA library in place of the default Nvidia libraries iGPU: integer indicates the GPU device to use, if set to None then device zero will be used first or the device set with setGPUID() ''' if (sAccelerationType not in lsTsgAccelTypes): raise TasmanianInputError("sAccelerationType", "ERROR: invalid acceleration type") if (iGPUID is None): pLibTSG.tsgEnableAcceleration(self.pGrid, bytes(sAccelerationType, encoding='utf8')) else: if ((iGPUID < 0) or (iGPUID >= self.getNumGPUs())): raise TasmanianInputError("iGPUID", "ERROR: invalid GPU ID number") pLibTSG.tsgEnableAccelerationGPU(self.pGrid, bytes(sAccelerationType, encoding='utf8'), iGPUID) def getAccelerationType(self): ''' returns the type of acceleration set by enableAcceleration ''' return str(pLibTSG.tsgGetAccelerationType(self.pGrid), encoding='utf8') def isAccelerationAvailable(self, sAccelerationType): ''' returns True if the library has been compiled with support for sAccelerationType. Even if this returns False, you can use the type for enableAcceleration, but the library will default to the next available type (see the Manual) ''' if (sAccelerationType not in lsTsgAccelTypes): raise TasmanianInputError("sAccelerationType", "ERROR: invalid acceleration type") return (pLibTSG.tsgIsAccelerationAvailable(bytes(sAccelerationType, encoding='utf8')) != 0) def setGPUID(self, iGPUID): ''' when using cuda on a machine with multiple GPUs, this helps set the GPU for this grid NOTE: each instance of the sparse grids class holds a separate instance of iGPUID and different grids can be assigned to different GPUs (on multi-gpu system) iGPUID can be changed at any time, however, this will cause some of the internal cache to be invalidated and it may lead to extraneous data movement calling read or make***Grid will reset the selected GPU defaults to 0 this doesn't do anything unless enableAcceleration is called using a "gpu-" acceleration type ''' if ((iGPUID < 0) or (iGPUID >= self.getNumGPUs())): raise TasmanianInputError("iGPUID", "ERROR: invalid GPU ID number") pLibTSG.tsgSetGPUID(self.pGrid, iGPUID) def getGPUID(self): ''' returns the GPU ID set using setGPUID ''' return pLibTSG.tsgGetGPUID(self.pGrid) def getNumGPUs(self): ''' returns the number of available GPUs according to cuda this is one of several functions designed to allow basic management of multi-gpu setup with only Tasmanian module ''' return pLibTSG.tsgGetNumGPUs() def getGPUMemory(self, iGPUID): ''' returns the total memory (in MegaBytes, 1024**2 bytes) of the corresponding GPU this is one of several functions designed to allow basic management of multi-gpu setup with only Tasmanian module ''' if ((iGPUID < 0) or (iGPUID >= self.getNumGPUs())): raise TasmanianInputError("iGPUID", "ERROR: invalid GPU ID number") return pLibTSG.tsgGetGPUMemory(iGPUID) def getGPUName(self, iGPUID): ''' return the cuda name ID of the corresponding GPU this is one of several functions designed to allow basic management of multi-gpu setup with only Tasmanian module ''' if ((iGPUID < 0) or (iGPUID >= self.getNumGPUs())): raise TasmanianInputError("iGPUID", "ERROR: invalid GPU ID number") pName = create_string_buffer(256) iNumChars = np.array([0], np.int32) pLibTSG.tsgGetGPUName(iGPUID, 256, pName, np.ctypeslib.as_ctypes(iNumChars)) return self.stringBufferToString(pName, iNumChars[0]) def printStats(self): ''' calls the library printStats() function, which displays basic information about this instance of the grid ''' pLibTSG.tsgPrintStats(self.pGrid) def plotPoints2D(self, pAxisObject=tsgPlot, sStyle="bo", iMarkerSize=3): ''' plots the points in a 2D plot using matplotlib.pyplot applicable only for grids with iDimensions == 2 pAxisObject: axis object from the matplotlib.pyplot package sStyle: string the matplotlib.pyplot style, e.g., 'ko' will make black cirlces, 'rx' will use red crosses iMarkerSize: positive integer the marker size for plotting the points ''' if (not bTsgPlotting): raise TasmanianInputError("plotPoints2D", "ERROR: could not load matplotlib.pyplot") if (self.getNumDimensions() != 2): raise TasmanianInputError("plotPoints2D", "ERROR: cannot plot a grid with other than 2 dimensions") aPoints = self.getPoints() fXmin = min(aPoints[:,0]) fXmax = max(aPoints[:,0]) fYmin = min(aPoints[:,1]) fYmax = max(aPoints[:,1]) if (fXmin == fXmax): fXmin = fXmin - 0.1 fXmax = fXmax + 0.1 if (fYmin == fYmax): fYmin = fYmin - 0.1 fYmax = fYmax + 0.1 pAxisObject.plot(aPoints[:,0], aPoints[:,1], sStyle, markersize=iMarkerSize) pAxisObject.axis([fXmin - 0.1 * np.fabs(fXmin), fXmax + 0.1 * np.fabs(fYmax), fYmin - 0.1 * np.fabs(fYmin), fYmax + 0.1 * np.fabs(fYmax)]) def plotResponse2D(self, iOutput=0, iNumDim0=100, iNumDim1=100, pAxisObject=tsgPlot, sCmap="jet"): ''' plots the response in a 2D plot using matplotlib.pyplot applicable only for grids with iDimensions == 2 iOutput is the output to use for plotting iNumDim0, iNumDim1: positive integers the points for the plot are selected on a dense grid with number of points iNumDim0 and iNumDim1 in dimensions 0 and 1 respectively pAxisObject: axis object from the matplotlib.pyplot package sCmap: string indicating the map to use, e.g., "jet" or "heat" ''' if (not bTsgPlotting): raise TasmanianInputError("plotResponse2D", "ERROR: could not load matplotlib.pyplot") if (iOutput < 0): raise TasmanianInputError("iOutput", "ERROR: iOutput should be a non-negative integer") if (iOutput >= self.getNumOutputs()): raise TasmanianInputError("iOutput", "ERROR: iOutput cannot exceed the index of the last output {0:1d}".format(self.getNumOutputs() - 1)) if (self.getNumDimensions() != 2): raise TasmanianInputError("plotResponse2D", "ERROR: cannot plot a grid with other than 2 dimensions") if (iNumDim0 < 1): raise TasmanianInputError("iNumDim0", "ERROR: the number of points should be at least 1") if (iNumDim1 < 1): raise TasmanianInputError("iNumDim1", "ERROR: the number of points should be at least 1") aPoints = self.getPoints() fXmin = min(aPoints[:,0]) fXmax = max(aPoints[:,0]) fYmin = min(aPoints[:,1]) fYmax = max(aPoints[:,1]) if (fXmin == fXmax): fXmin = fXmin - 0.1 fXmax = fXmax + 0.1 if (fYmin == fYmax): fYmin = fYmin - 0.1 fYmax = fYmax + 0.1 x = np.linspace(fXmin, fXmax, iNumDim0) y = np.linspace(fYmax, fYmin, iNumDim1) # flip the order of y to match the top-to-bottom pixel indexing XX, YY = np.meshgrid(x, y) ZZ = self.evaluateBatch(np.vstack((XX.reshape((iNumDim0*iNumDim1,)), YY.reshape((iNumDim0*iNumDim1,)))).T) ZZ = ZZ[:,iOutput].reshape((iNumDim0,iNumDim1)) pAxisObject.imshow(ZZ, cmap=sCmap, extent=[fXmin, fXmax, fYmin, fYmax]) def __testMakeGlobalGrid(self, iDimension, iOutputs, iDepth, sType, liAnisotropicWeights, liLevelLimits): ''' Tests the correctness of makeGlobalGrid() and its variants. ''' if (iDimension <= 0): raise TasmanianInputError("iDimension", "ERROR: dimension should be a positive integer") if (iOutputs < 0): raise TasmanianInputError("iOutputs", "ERROR: outputs should be a non-negative integer") if (iDepth < 0): raise TasmanianInputError("iDepth", "ERROR: depth should be a non-negative integer") if (sType not in lsTsgGlobalTypes): raise TasmanianInputError("sType", "ERROR: invalid type, see TasmanianSG.lsTsgGlobalTypes for list of accepted types") if (len(liAnisotropicWeights) > 0): iNumWeights = 2*iDimension if sType in lsTsgCurvedTypes else iDimension if (len(liAnisotropicWeights) != iNumWeights): raise TasmanianInputError("liAnisotropicWeights", "ERROR: wrong number of liAnisotropicWeights, sType '{0:s}' needs {1:1d} " "weights but len(liAnisotropicWeights) == {2:1d}".format(sType, iNumWeights, len(liAnisotropicWeights))) if (len(liLevelLimits) > 0): if (len(liLevelLimits) != iDimension): raise TasmanianInputError("liLevelLimits", "ERROR: invalid number of level limits, must be equal to iDimension") def makeGlobalGrid(iDimension, iOutputs, iDepth, sType, sRule, liAnisotropicWeights=[], fAlpha=0.0, fBeta=0.0, sCustomFilename="", liLevelLimits=[]): ''' Factory method equivalent to TasmanianSparseGrid.makeGlobalGrid(). ''' grid = TasmanianSparseGrid() grid.makeGlobalGrid(iDimension, iOutputs, iDepth, sType, sRule, liAnisotropicWeights, fAlpha, fBeta, sCustomFilename, liLevelLimits) return grid def makeSequenceGrid(iDimension, iOutputs, iDepth, sType, sRule, liAnisotropicWeights=[], liLevelLimits=[]): ''' Factory method equivalent to TasmanianSparseGrid.makeSequenceGrid(). ''' grid = TasmanianSparseGrid() grid.makeSequenceGrid(iDimension, iOutputs, iDepth, sType, sRule, liAnisotropicWeights, liLevelLimits) return grid def makeFourierGrid(iDimension, iOutputs, iDepth, sType, liAnisotropicWeights=[], liLevelLimits=[]): ''' Factory method equivalent to TasmanianSparseGrid.makeFourierGrid(). ''' grid = TasmanianSparseGrid() grid.makeFourierGrid(iDimension, iOutputs, iDepth, sType, liAnisotropicWeights, liLevelLimits) return grid def makeLocalPolynomialGrid(iDimension, iOutputs, iDepth, iOrder=1, sRule="localp", liLevelLimits=[]): ''' Factory method equivalent to TasmanianSparseGrid.makeLocalPolynomialGrid(). ''' grid = TasmanianSparseGrid() grid.makeLocalPolynomialGrid(iDimension, iOutputs, iDepth, iOrder, sRule, liLevelLimits) return grid def makeWaveletGrid(iDimension, iOutputs, iDepth, iOrder=1, liLevelLimits=[]): ''' Factory method equivalent to TasmanianSparseGrid.makeWaveletGrid(). ''' grid = TasmanianSparseGrid() grid.makeWaveletGrid(iDimension, iOutputs, iDepth, iOrder, liLevelLimits) return grid def makeGlobalGridCustom(iDimension, iOutputs, iDepth, sType, pCustomTabulated, liAnisotropicWeights=[], liLevelLimits=[]): ''' Factory method equivalent to TasmanianSparseGrid.makeGlobalGridCustom(). ''' grid = TasmanianSparseGrid() grid.makeGlobalGridCustom(iDimension, iOutputs, iDepth, sType, pCustomTabulated, liAnisotropicWeights, liLevelLimits) return grid def copyGrid(source, iOutputsBegin = 0, iOutputsEnd = -1): ''' Factory method equivalent to TasmanianSparseGrid.copyGrid(). ''' grid = TasmanianSparseGrid() grid.copyGrid(source, iOutputsBegin, iOutputsEnd) return grid def check_np_arr(np_data_name, np_data, expected_length, expected_dimension): ''' Utility function that checks if a NumPy array conforms to given input lengths and dimensions. ''' if len(np_data.shape) != expected_dimension: raise TasmanianInputError(np_data_name, "ERROR: the dimension of " + np_data_name + " does not match the expected dimension of " + str(expected_dimension)) if len(np_data) != expected_length: raise TasmanianInputError(np_data_name, "ERROR: the length of " + np_data_name + " does not match the expected length of " + str(expected_length)) class CustomTabulated: def __init__(self): ''' Constructor that creates an empty CustomTabulated instance. ''' self.CustomTabulatedObject = True self.pCustomTabulated = pLibTSG.tsgConstructCustomTabulated() def __del__(self): ''' Destructor that calls the C++ destructor and releases all memory used by this instance of the class. Make sure to call this to avoid memory leaks. ''' pLibTSG.tsgDestructCustomTabulated(self.pCustomTabulated) def read(self, sFilename): ''' Reads the CustomTabulated object from a file and discards any existing grid held by this class. sFilename: string indicating a CustomTabulated that was already written using write from Python or any other Tasmanian interfaces. output: boolean True: the read was successful False: the read failed, check the CLI output for an error message ''' if pLibTSG.tsgReadCustomTabulated(self.pCustomTabulated, bytes(sFilename, encoding='utf8')) == 0: raise TasmanianInputError("sFilename", "ERROR: {0:1s} does not appear to be a valid Tasmanian file.".format(sFilename)) def write(self, sFilename): ''' Writes the CustomTabulated object to a file in ASCII format. sFilename: string indicating a location where the CustomTabulated instance will be written to. ''' pLibTSG.tsgWriteCustomTabulated(self.pCustomTabulated, bytes(sFilename, encoding='utf8')) def getNumLevels(self): return pLibTSG.tsgGetNumLevelsCustomTabulated(self.pCustomTabulated) def getNumPoints(self, level): return pLibTSG.tsgGetNumPointsCustomTabulated(self.pCustomTabulated, c_int(level)) def getIExact(self, level): return pLibTSG.tsgGetIExactCustomTabulated(self.pCustomTabulated, c_int(level)) def getQExact(self, level): return pLibTSG.tsgGetQExactCustomTabulated(self.pCustomTabulated, c_int(level)) def getDescription(self): return pLibTSG.tsgGetDescriptionCustomTabulated(self.pCustomTabulated).decode('UTF-8') def getWeightsNodes(self, level): ''' Outputs the weights and nodes (in that order) of the CustomTabulated instance for a given level. level: int indicating the level where the weights/nodes will be pulled from. output: int (weights), int (nodes) ''' iNumPoints = self.getNumPoints(level) if (iNumPoints == 0): return np.empty([0], np.float64), np.empty([0], np.float64) pWeights, pNodes = (iNumPoints * c_double)(), (iNumPoints * c_double)() pLibTSG.tsgGetWeightsNodesStaticCustomTabulated(self.pCustomTabulated, c_int(level), pWeights, pNodes) return np.array(pWeights), np.array(pNodes) def makeCustomTabulatedFromFile(filename): ''' Wrapper that calls the CustomTabulated constructor which reads its data from a file. filename: string indicating the location of the file. output: CustomTabulated ''' ct = CustomTabulated() ct.read(filename) return ct def makeCustomTabulatedFromData(num_levels, num_nodes, precision, nodes, weights, description): ''' Wrapper that calls the CustomTabulated constructor which takes ownership of its input data. num_levels: int indicating the number of levels of the instance. num_nodes: 1D NumPy array of length num_levels whose i-th entry is the number of nodes at level i. precision: 1D NumPy array of length num_levels whose i-th entry is the (quadrature/integration) precision at level i. nodes: Python list of length num_levels whose i-th entry is a 1D NumPy array containing the nodes at level i. weights: Python list of length num_levels whose i-th entry is a 1D NumPy array containing the quadrature weights at level i. description: string that briefly describes the instance. output: CustomTabulated ''' # nodes and weights are expected to be Python lists. if len(nodes) != num_levels: raise TasmanianInputError("nodes", "ERROR: the length of nodes does not match the expected length " + str(num_levels)) if len(weights) != num_levels: raise TasmanianInputError("weights", "ERROR: the length of weights does not match the expected length " + str(num_levels)) check_np_arr("num_nodes", num_nodes, num_levels, 1); check_np_arr("precision", precision, num_levels, 1); for i in range(num_levels): check_np_arr("nodes["+str(i)+"]", nodes[i], num_nodes[i], 1); check_np_arr("weights["+str(i)+"]", weights[i], num_nodes[i], 1); ct = CustomTabulated() # create the C arrays for num_nodes, precision, nodes, and weights by copying. pNumNodes, pPrecision, pNodes, pWeights = None, None, None, None if (num_levels > 0): pNumNodes = (c_int * num_levels)() pPrecision = (c_int * num_levels)() for iI in range(num_levels): pNumNodes[iI] = num_nodes[iI] pPrecision[iI] = precision[iI] total_num_nodes = np.sum(num_nodes) pNodes = (c_double * total_num_nodes)() node_idx = 0 for lfJ in nodes: for fK in lfJ: pNodes[node_idx] = fK node_idx += 1 pWeights = (c_double * total_num_nodes)() weight_idx = 0 for lfJ in weights: for fK in lfJ: pWeights[weight_idx] = fK weight_idx += 1 ct.pCustomTabulated = pLibTSG.tsgMakeCustomTabulatedFromData(c_int(num_levels), pNumNodes, pPrecision, pNodes, pWeights, bytes(description, encoding='utf8')) return ct def makeCustomTabulatedSubset(pCustomTabulated, iStartIndex, iStride, sDescription): ''' Wrapper that creates a subset of an input CustomTabulated object. Specifically, it chooses the levels that start at iStartIndex with displacement given by iStride. pCustomTabulated: CustomTabulated instance to take the subset of. iStartIndex: starting index of the subset. iStride: distance between the levels of the subset. description: string that briefly describes the subset. output: CustomTabulated ''' if not hasattr(pCustomTabulated, "CustomTabulatedObject"): raise TasmanianInputError("pCustomTabulated", "ERROR: pCustomTabulated must be an instance of CustomTabulated") if (iStartIndex < 0 | iStartIndex >= pCustomTabulated.getNumLevels()): raise TasmanianInputError("iStartIndex", "ERROR: iStartIndex must be between 0 and " + str(pCustomTabulated.getNumLevels())) if (iStride <= 0): raise TasmanianInputError("iStride", "ERROR: iStride must be positive") ct = CustomTabulated() ct.pCustomTabulated = pLibTSG.tsgGetSubrules(c_void_p(pCustomTabulated.pCustomTabulated), c_int(iStartIndex), c_int(iStride), bytes(sDescription, encoding='utf8')) return(ct) TASMANIAN-8.1/InterfacePython/example_dream.in.py000077500000000000000000000065011470551176200215760ustar00rootroot00000000000000#!@Tasmanian_string_python_hashbang@ ############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## # The sys.path.append() command is necessary only if Tasmanian is # not included in the system PYTHONPATH # If PYTHONPATH is set (e.g., source TasmanianENVsetup.sh) you can jump # straight to import Tasmanian import sys @Tasmanian_python_example_import@ import Tasmanian import example_dream_01 import example_dream_02 import example_dream_03 import example_dream_04 import example_dream_05 if __name__ == "__main__": example_dream_01.example_01() example_dream_02.example_02() if len(sys.argv) < 2: # if running a long test example_dream_03.example_03() example_dream_04.example_04() example_dream_05.example_05() print("") TASMANIAN-8.1/InterfacePython/example_dream_01.py000066400000000000000000000116721470551176200214730ustar00rootroot00000000000000#!@Tasmanian_string_python_hashbang@ ############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from Tasmanian import DREAM import numpy def example_01(): print("\n---------------------------------------------------------------------------------------------------\n") print("EXAMPLE 1: make your own probability distribution") print(" sample from the Gaussian distribution: f(x) = exp(-x^2)") print(" ignoring scaling constants, using 3000 samples") print(" See the comments in example_dream_01.cpp\n") iNumDimensions = 1 iNumChains = 30 iNumBurnupIterations = 200 iNumCollectIterations = 1000 # total samples are iNumChains x iNumCollectIterations state = DREAM.State(iNumChains, GridOrIntDimensions = iNumDimensions) # initialize with uniform samples on [-2, 2] state.setState(DREAM.genUniformSamples((-2.0,), (2.0,), state.getNumChains())) DREAM.Sample(iNumBurnupIterations, iNumCollectIterations, lambda x : numpy.exp( - x[:,0]**2 ), # Gaussian mean 0.0 variance 0.5 DREAM.Domain("unbounded"), state, DREAM.IndependentUpdate("uniform", 0.5), DREAM.DifferentialUpdate(90)) aMean, aVariance = state.getHistoryMeanVariance() print("Using regular form:") print("mean {0:13.6f} error {1:14.6e}".format(aMean[0], numpy.abs(aMean[0]))) print("variance{0:13.6f} error {1:14.6e}".format(aVariance[0], numpy.abs(aVariance[0] -0.5))) # reset the state state = DREAM.State(iNumChains, GridOrIntDimensions = iNumDimensions) # initialize with uniform samples on [-2, 2] state.setState(DREAM.genUniformSamples((-2.0,), (2.0,), state.getNumChains())) DREAM.Sample(iNumBurnupIterations, iNumCollectIterations, lambda x : - x[:,0]**2, # Gaussian mean 0.0 variance 0.5 DREAM.Domain("unbounded"), state, DREAM.IndependentUpdate("uniform", 0.5), DREAM.DifferentialUpdate(90), typeForm = DREAM.typeLogform) aMean, aVariance = state.getHistoryMeanVariance() print("Using logarithm form:") print("mean {0:13.6f} error {1:14.6e}".format(aMean[0], numpy.abs(aMean[0]))) print("variance{0:13.6f} error {1:14.6e}".format(aVariance[0], numpy.abs(aVariance[0] -0.5))) if __name__ == "__main__": example_01() TASMANIAN-8.1/InterfacePython/example_dream_02.py000066400000000000000000000151771470551176200215000ustar00rootroot00000000000000#!@Tasmanian_string_python_hashbang@ ############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from Tasmanian import DREAM from Tasmanian import SparseGrid from Tasmanian import makeGlobalGrid from Tasmanian import makeSequenceGrid from Tasmanian import loadNeededPoints import numpy def example_02(): print("\n---------------------------------------------------------------------------------------------------\n") print("EXAMPLE 2: set the inference problem: identify model parameters x_0 and x_1") print(" from data (noise free example)") print(" model: f(x) = sin(x_0*M_PI*t + x_1), data: d = sin(M_PI*t + 0.3*M_PI)") print(" t in [0,1], t is discretized with 32 equidistant nodes") print(" the likelihood is exp(- 16 * (f(x) - d)^2)") print(" using a sparse grid to interpolate the likelihood") print(" NOTE: See the comments in the C++ DREAM Example 2\n") iNumDimensions = 2; iNumChains = 100; iNumBurnupIterations = 3000; iNumCollectIterations = 100; def model(aX): # using 32 nodes in the interior of (0.0, 1.0) t = numpy.linspace(1.0 / 64.0, 1.0 - 1.0 / 64.0, 32) return numpy.sin(numpy.pi * aX[0] * t + aX[1]) def likelihood(aY, aData): # using log-form likelihood # numpy.ones((1,)) converts the scalar to a 1D numpy array return - 0.5 * len(aData) * numpy.sum((aY - aData)**2) * numpy.ones((1,)) aData = model([1.0, 0.3 * numpy.pi]) domain_lower = numpy.array([0.5, -0.1]) domain_upper = numpy.array([8.0, 1.7]) grid = makeGlobalGrid(iNumDimensions, 1, 10, 'iptotal', 'clenshaw-curtis') grid.setDomainTransform(numpy.column_stack([domain_lower, domain_upper])) loadNeededPoints(lambda x, tid : likelihood(model(x), aData), grid, iNumThreads = 2) state = DREAM.State(iNumChains, grid) state.setState(DREAM.genUniformSamples(domain_lower, domain_upper, state.getNumChains())) DREAM.Sample(iNumBurnupIterations, iNumCollectIterations, lambda x : grid.evaluateBatch(x).reshape((x.shape[0],)), # link to the SparseGrid DREAM.Domain(grid), state, DREAM.IndependentUpdate("uniform", 0.5), DREAM.DifferentialUpdate(90), typeForm = DREAM.typeLogform) aMean, aVariance = state.getHistoryMeanVariance() print("Inferred values (using 10th order polynomial sparse grid):") print(" frequency:{0:13.6f} error:{1:14.6e}".format(aMean[0], numpy.abs(aMean[0] - 1.0))) print(" correction:{0:13.6f} error:{1:14.6e}\n".format(aMean[1], numpy.abs(aMean[0] - 0.3 * numpy.pi))) # repeat the example using the faster Sequence grid and 30th order polynomials grid = makeSequenceGrid(iNumDimensions, 1, 30, 'iptotal', 'leja') grid.setDomainTransform(numpy.column_stack([domain_lower, domain_upper])) loadNeededPoints(lambda x, tid : likelihood(model(x), aData), grid, iNumThreads = 2) state = DREAM.State(iNumChains, grid) state.setState(DREAM.genUniformSamples(domain_lower, domain_upper, state.getNumChains())) DREAM.Sample(iNumBurnupIterations, iNumCollectIterations, lambda x : grid.evaluateBatch(x).reshape((x.shape[0],)), # link to the SparseGrid DREAM.Domain(grid), state, DREAM.IndependentUpdate("uniform", 0.5), DREAM.DifferentialUpdate(90), typeForm = DREAM.typeLogform) aMean, aVariance = state.getHistoryMeanVariance() print("Inferred values (using 30th order polynomial sparse grid):") print(" frequency:{0:13.6f} error:{1:14.6e}".format(aMean[0], numpy.abs(aMean[0] - 1.0))) print(" correction:{0:13.6f} error:{1:14.6e}".format(aMean[1], numpy.abs(aMean[0] - 0.3 * numpy.pi))) if __name__ == "__main__": example_02() TASMANIAN-8.1/InterfacePython/example_dream_03.py000066400000000000000000000145151470551176200214740ustar00rootroot00000000000000#!@Tasmanian_string_python_hashbang@ ############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from Tasmanian import DREAM from Tasmanian import SparseGrid from Tasmanian import makeSequenceGrid from Tasmanian import loadNeededPoints import numpy def example_03(): print("\n---------------------------------------------------------------------------------------------------\n") print("EXAMPLE 3: set the inference problem: identify x_0 and x_1 model parameters") print(" from data (noise free example)") print(" model: f(x) = sin(x_0*M_PI*t + x_1),") print(" data: d = sin(5*M_PI*t + 0.3*M_PI) + sin(10*M_PI*t + 0.1*M_PI)") print(" compared to Example 2, the data is a superposition of two signals") print(" and the posterior is multi-modal") print(" -- problem setup --") print(" t in [0,1], t is discretized with 32 equidistant nodes") print(" the likelihood is exp(- 16 * (f(x) - d)^2)") print(" using a sparse grid to interpolate the model\n") iNumDimensions = 2 iNumOutputs = 32 iNumChains = 500 iNumBurnupIterations = 1000 iNumCollectIterations = 300 def model(aX): # using 32 nodes in the interior of (0.0, 1.0) t = numpy.linspace(1.0 / 64.0, 1.0 - 1.0 / 64.0, 32) return numpy.sin(numpy.pi * aX[0] * t + aX[1]) aData = model([5.0, 0.3 * numpy.pi]) + model([10.0, 0.1 * numpy.pi]) grid = makeSequenceGrid(iNumDimensions, iNumOutputs, 30, 'iptotal', 'leja') domain_lower = numpy.array([ 1.0, -0.1]) domain_upper = numpy.array([12.0, 1.7]) grid.setDomainTransform(numpy.column_stack([domain_lower, domain_upper])) loadNeededPoints(lambda x, tid : model(x), grid, 2) likely = DREAM.LikelihoodGaussIsotropic(1.0 / float(iNumOutputs), aData) state = DREAM.State(iNumChains, grid) state.setState(DREAM.genUniformSamples(domain_lower, domain_upper, state.getNumChains())) DREAM.Sample(iNumBurnupIterations, iNumCollectIterations, DREAM.Posterior(grid, likely, prior = "uniform", typeForm = DREAM.typeLogform), DREAM.Domain(grid), state, DREAM.IndependentUpdate("gaussian", 0.01), DREAM.DifferentialUpdate(90), typeForm = DREAM.typeLogform) aSamples = state.getHistory() # split the frequencies into low and high for the two modes of the posterior # here 6.5 is the mid-point of the domain low_frequency = numpy.average(numpy.array( [aSamples[i,0] for i in range(aSamples.shape[0]) if aSamples[i,0] < 6.5] )) low_correction = numpy.average(numpy.array( [aSamples[i,1] for i in range(aSamples.shape[0]) if aSamples[i,0] < 6.5] )) high_frequency = numpy.average(numpy.array( [aSamples[i,0] for i in range(aSamples.shape[0]) if aSamples[i,0] >= 6.5] )) high_correction = numpy.average(numpy.array( [aSamples[i,1] for i in range(aSamples.shape[0]) if aSamples[i,0] >= 6.5] )) print("Inferred values:") print(" low frequency:{0:13.6f} error:{1:14.6e}".format(low_frequency, numpy.abs(low_frequency - 5.0))) print(" low correction:{0:13.6f} error:{1:14.6e}\n".format(low_correction, numpy.abs(low_correction - 0.3 * numpy.pi))) print(" high frequency:{0:13.6f} error:{1:14.6e}".format(high_frequency, numpy.abs(high_frequency - 10.0))) print(" high correction:{0:13.6f} error:{1:14.6e}".format(high_correction, numpy.abs(high_correction - 0.1 * numpy.pi))) if __name__ == "__main__": example_03() TASMANIAN-8.1/InterfacePython/example_dream_04.py000066400000000000000000000151401470551176200214700ustar00rootroot00000000000000#!@Tasmanian_string_python_hashbang@ ############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from Tasmanian import DREAM from Tasmanian import SparseGrid from Tasmanian import makeSequenceGrid from Tasmanian import loadNeededValues import numpy def example_04(): print("\n---------------------------------------------------------------------------------------------------\n") print("EXAMPLE 4: similar to Example 3, but the data is noisy and the multi-modal posterior comes") print(" from a symmetry in the model") print(" set inference problem: identify x_0, x_1, x_2 and x_3 (four) model parameters") print(" from noisy data") print(" model: f(x) = x_0*exp(x_1*t) + x_2*exp(x_3*t), data: d = exp(t) + 0.4*exp(3*t)") print(" note the symmetry between x_1 and x_3 which results in a bi-modal posterior") print(" t in [0,1], t is discretized with 64 equidistant nodes") print(" likelihood is exp(-64 * (f(x) - d)^2)") print(" using a sparse grid to interpolate the model\n") iNumDimensions = 4 iNumOutputs = 64 iNumChains = 50 iNumBurnupIterations = 1000 iNumCollectIterations = 1000 def model(aX): # using 64 nodes in the interior of (0.0, 1.0) t = numpy.linspace(1.0 / 128.0, 1.0 - 1.0 / 128.0, 64) return aX[0] * numpy.exp(aX[1] * t) + aX[2] * numpy.exp(aX[3] * t) aData = (model([1.0, 1.0, 0.4, 3.0]) # add noise + DREAM.genGaussianSamples([0.0 for i in range(iNumOutputs)], [1.0 / float(iNumOutputs) for i in range(iNumOutputs)], 1).reshape((iNumOutputs,))) grid = makeSequenceGrid(iNumDimensions, iNumOutputs, 15, 'iptotal', 'leja') domain_lower = numpy.array([0.2, 0.5, 0.2, 0.5]) domain_upper = numpy.array([1.2, 4.0, 1.2, 4.0]) grid.setDomainTransform(numpy.column_stack([domain_lower, domain_upper])) loadNeededValues(lambda x, tid : model(x), grid, 1) likely = DREAM.LikelihoodGaussIsotropic(1.0 / float(iNumOutputs), aData) state = DREAM.State(iNumChains, grid) state.setState(DREAM.genUniformSamples(domain_lower, domain_upper, state.getNumChains())) DREAM.Sample(iNumBurnupIterations, iNumCollectIterations, DREAM.Posterior(grid, likely, prior = "uniform", typeForm = DREAM.typeLogform), DREAM.Domain(grid), state, DREAM.IndependentUpdate("gaussian", 0.01), DREAM.DifferentialUpdate(100), typeForm = DREAM.typeLogform) aSamples = state.getHistory() low_scale = numpy.average(numpy.array( [aSamples[i,0] if aSamples[i,1] < aSamples[i,3] else aSamples[i,2] for i in range(aSamples.shape[0])] )) low_rate = numpy.average(numpy.array( [aSamples[i,1] if aSamples[i,1] < aSamples[i,3] else aSamples[i,3] for i in range(aSamples.shape[0])] )) high_scale = numpy.average(numpy.array( [aSamples[i,0] if aSamples[i,1] >= aSamples[i,3] else aSamples[i,2] for i in range(aSamples.shape[0])] )) high_rate = numpy.average(numpy.array( [aSamples[i,1] if aSamples[i,1] >= aSamples[i,3] else aSamples[i,3] for i in range(aSamples.shape[0])] )) print("Acceptance rate: {0:1.3f}".format(state.getAcceptanceRate())) print("Inferred values:") print(" low rate:{0:13.6f} error:{1:14.6e}".format(low_rate, numpy.abs(low_rate - 1.0))) print(" low scale:{0:13.6f} error:{1:14.6e}\n".format(low_scale, numpy.abs(low_scale - 1.0))) print(" high rate:{0:13.6f} error:{1:14.6e}".format(high_rate, numpy.abs(high_rate - 3.0))) print(" high scale:{0:13.6f} error:{1:14.6e}".format(high_scale, numpy.abs(high_scale - 0.4))) if __name__ == "__main__": example_04() TASMANIAN-8.1/InterfacePython/example_dream_05.py000066400000000000000000000157241470551176200215010ustar00rootroot00000000000000#!@Tasmanian_string_python_hashbang@ ############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from Tasmanian import DREAM import numpy def example_05(): print("\n---------------------------------------------------------------------------------------------------\n") print("EXAMPLE 5: infer the frequency and magnitude of two signals from noisy data") print(" the model has 5 parameters: f(x_1 ... x_5) = sum x_k sin(k * pi * t)") print(" data = 2.0 * sin(2 * pi * t) + sin(4 * pi * t) + noise") print(" t in [0, 1], t is discretized using 64 equidistant nodes") print(" using two different likelihood functions, corresponding to l-2 and l-1 norms") print(" looking for the mode of the posterior, i.e., the optimal fit to the data\n") iNumDimensions = 5 iNumChains = 50 iNumBurnupIterations = 1000 iNumCollectIterations = 1000 fScaleT = 1.0 / 64.0 # scale in T def model(aX): # the model assumes 2D array aX t = numpy.linspace(1.0 / 128.0, 1.0 - 1.0 / 128.0, 64) aSinMatrix = numpy.column_stack([numpy.sin(float(k) * numpy.pi * t) for k in range(1, 6)]) return numpy.matmul(aSinMatrix, aX.transpose()).transpose() aNominalWeights = numpy.array([0.0, 2.0, 0.0, 1.0, 0.0]) aData = model(aNominalWeights).reshape((64,)) aData = aData + DREAM.genUniformSamples([-fScaleT for i in range(64)], [fScaleT for i in range(64)], 1).reshape((64,)) likely = DREAM.LikelihoodGaussIsotropic(fScaleT, aData) domain_lower = numpy.array([0.0 for i in range(iNumDimensions)]) domain_upper = numpy.array([3.0 for i in range(iNumDimensions)]) state = DREAM.State(iNumChains, iNumDimensions) state.setState(DREAM.genUniformSamples(domain_lower, domain_upper, state.getNumChains())) DREAM.Sample(iNumBurnupIterations, iNumCollectIterations, DREAM.Posterior(model, likely, prior = "uniform", typeForm = DREAM.typeLogform), DREAM.Domain("hypercube", domain_lower, domain_upper), state, DREAM.IndependentUpdate("uniform", 0.0), DREAM.DifferentialUpdate(100), typeForm = DREAM.typeLogform) aSolution = state.getApproximateMode() sResult = "" sErrors = "" for i in range(iNumDimensions): sResult = "{0:1s}{1:13.5f}".format(sResult, aSolution[i]) sErrors = "{0:1s}{1:13.5e}".format(sErrors, numpy.abs(aSolution[i] - aNominalWeights[i])) print("Using Gaussian likelihood, the computed solution is:") print(" computed: {0:1s}".format(sResult)) print(" error: {0:1s}".format(sErrors)) ############################################################################################### # repeat the example, but change the likelihood ############################################################################################### def l1likelihood(aX, aData): # computes the likelihood, the 32 comes from the discretization in t aY = model(aX) aResult = numpy.empty((aY.shape[0],), numpy.float64) for i in range(aY.shape[0]): aResult[i] = -32.0 * numpy.sum(numpy.abs(aY[i,:] - aData)) return aResult state = DREAM.State(iNumChains, iNumDimensions) # reset the state state.setState(DREAM.genUniformSamples(domain_lower, domain_upper, state.getNumChains())) DREAM.Sample(iNumBurnupIterations, iNumCollectIterations, DREAM.PosteriorEmbeddedLikelihood(lambda x : l1likelihood(x, aData), prior = "uniform", typeForm = DREAM.typeLogform), DREAM.Domain("hypercube", domain_lower, domain_upper), state, DREAM.IndependentUpdate("uniform", 0.0), DREAM.DifferentialUpdate(100), typeForm = DREAM.typeLogform) aSolution = state.getApproximateMode() sResult = "" sErrors = "" for i in range(iNumDimensions): sResult = "{0:1s}{1:13.5f}".format(sResult, aSolution[i]) sErrors = "{0:1s}{1:13.5e}".format(sErrors, numpy.abs(aSolution[i] - aNominalWeights[i])) print("\nUsing l-1 likelihood, the computed solution is:") print(" computed: {0:1s}".format(sResult)) print(" error: {0:1s}".format(sErrors)) if __name__ == "__main__": example_05() TASMANIAN-8.1/InterfacePython/example_optimization.in.py000077500000000000000000000061511470551176200232350ustar00rootroot00000000000000#!@Tasmanian_string_python_hashbang@ ############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## # The sys.path.append() command is necessary only if Tasmanian is # not included in the system PYTHONPATH # If PYTHONPATH is set (e.g., source TasmanianENVsetup.sh) you can jump # straight to import Tasmanian import sys @Tasmanian_python_example_import@ import Tasmanian import example_optimization_01 import example_optimization_02 if __name__ == "__main__": example_optimization_01.example_01() example_optimization_02.example_02() print("") TASMANIAN-8.1/InterfacePython/example_optimization_01.py000066400000000000000000000137571470551176200231370ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from Tasmanian import Optimization as Opt, DREAM, makeLocalPolynomialGrid import numpy as np def example_01(): print("\n---------------------------------------------------------------------------------------------------\n") print("EXAMPLE 1: use the Particle Swarm algorithm to minimize the six-hump camel function") # Create an empty Particle Swarm state. iNumDimensions = 2 iNumParticles = 50 randUnif = DREAM.RandomGenerator(sType="default", iSeed=777) state = Opt.ParticleSwarmState(iNumDimensions, iNumParticles) # Load the state with uniformly initialized particles in the domain [-3.0, 3.0] x [-2.0, 2.0]. state.initializeParticlesInsideBox(np.array([-3.0, -2.0]), np.array([3.0, 2.0]), random01=randUnif) # Define the batched objective function `func` and a function `inside` that returns True if its input is inside the domain. # NOTE: `shc` is the unbatched six-hump camel function. shc = lambda x : (4 - 2.1*x[0]*x[0] + x[0]*x[0]*x[0]*x[0]/3)*x[0]*x[0] + x[0]*x[1] + (-4.0 + 4.0*x[1]*x[1])*x[1]*x[1] func = lambda x_batch : np.apply_along_axis(shc, 1, x_batch) inside = lambda x : bool((-3 <= x[0]) and (x[0] <= 3) and (-2 <= x[1]) and (x[1] <= 2)) # Run the Particle Swarm (PS) algorithm and check the output. iNumIterations = 200; Opt.ParticleSwarm(func, inside, 0.5, 2, 2, iNumIterations, state, random01=randUnif) aLocal1 = np.array([-0.08984201368301331, +0.7126564032704135]) aLocal2 = np.array([+0.08984201368301331, -0.7126564032704135]) aSolution = state.getBestPosition() sResult = "" fL2Error = 0.0 for i in range(iNumDimensions): sResult = "{0:1s}{1:13.5f}".format(sResult, aSolution[i]) fL2Error += min((aSolution[i] - aLocal1[i]) ** 2, (aSolution[i] - aLocal2[i]) ** 2) fL2Error = np.sqrt(fL2Error) print("\nUsing the Particle Swarm algorithm on the EXACT objective function, the computed solution is:") print(" computed: {0:1s}".format(sResult)) print(" L2 error: {0:14e}".format(fL2Error)) # Create a surrogate model for the six-hump camel function. grid = makeLocalPolynomialGrid(2, 1, 10, iOrder=1) grid.setDomainTransform(np.array([[-3.0, 3.0], [-2.0, 2.0]])) # set the non-canonical domain needed_points = grid.getNeededPoints() needed_values = np.resize(func(needed_points), [grid.getNumNeeded(), 1]) grid.loadNeededValues(needed_values) surrogate_func = lambda x_batch : np.squeeze(grid.evaluateBatch(x_batch)) # Run the PS algorithm on the surrogate and check the output. state = Opt.ParticleSwarmState(iNumDimensions, iNumParticles) state.initializeParticlesInsideBox(np.array([-3.0, -2.0]), np.array([3.0, 2.0]), random01=randUnif) Opt.ParticleSwarm(surrogate_func, inside, 0.5, 2, 2, iNumIterations, state, random01=randUnif) aSolution = state.getBestPosition() sResult = "" fL2Error = 0.0 for i in range(iNumDimensions): sResult = "{0:1s}{1:13.5f}".format(sResult, aSolution[i]) fL2Error += min((aSolution[i] - aLocal1[i]) ** 2, (aSolution[i] - aLocal2[i]) ** 2) fL2Error = np.sqrt(fL2Error) print("\nUsing the Particle Swarm algorithm on the SURROGATE objective function, the computed solution is:") print(" computed: {0:1s}".format(sResult)) print(" L2 error: {0:14e}".format(fL2Error)) if __name__ == "__main__": example_01() TASMANIAN-8.1/InterfacePython/example_optimization_02.py000066400000000000000000000161631470551176200231320ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## from Tasmanian import Optimization as Opt, makeGlobalGrid import numpy as np def example_02(): print("\n---------------------------------------------------------------------------------------------------\n") print("EXAMPLE 2: use various Gradient Descent algorithms to minimize a convex quadratic") # Define the objective function `func` and and its gradient `grad`. func = lambda x : 2.0 * (x[0] - 1.0) * (x[0] - 1.0) + (x[1] - 2.0) * (x[1] - 2.0) / 2.0 grad = lambda x : np.array([4.0 * (x[0] - 1.0), x[1] - 2.0]) # Create an empty Gradient Descent State. x0 = np.array([0.0, 0.0]) state = Opt.GradientDescentState(x0, 0.0) # Run the Gradient Descent (GD) algorithm and check the output. Note that the adaptive stepsize in the state is NOT used. iNumIterations = 200; fTolerance = 1E-3 dInfo = Opt.GradientDescent(grad, 1/8.0, iNumIterations, fTolerance, state) aGlobal = np.array([1.0, 2.0]) aSolution = state.getX() sResult = "" fL2Error = 0.0 for i in range(2): sResult = "{0:1s}{1:13.5f}".format(sResult, aSolution[i]) fL2Error += (aSolution[i] - aGlobal[i]) ** 2 fL2Error = np.sqrt(fL2Error) print("\nUsing the Gradient Descent algorithm on the EXACT objective function, the computed solution is:") print(" iterations: {0:14}".format(dInfo['performed_iterations'])) print(" computed: {0:1s}".format(sResult)) print(" L2 error: {0:14e}".format(fL2Error)) # Create a surrogate model for the quadratic. # NOTE: local polynomial grids are not well suited for first-order methods like gradient descent. grid = makeGlobalGrid(2, 1, 2, "iptotal", "leja") needed_points = grid.getNeededPoints() needed_values = np.resize(np.apply_along_axis(func, 1, needed_points), [grid.getNumNeeded(), 1]) grid.loadNeededValues(needed_values) surrogate_func = lambda x : grid.evaluate(x) surrogate_grad = lambda x : grid.differentiate(x) # Run the GD algorithm on the surrogate and check the output. state = Opt.GradientDescentState(x0, 0.0) dInfo = Opt.GradientDescent(surrogate_grad, 1/8.0, iNumIterations, fTolerance, state) aSolution = state.getX() sResult = "" fL2Error = 0.0 for i in range(2): sResult = "{0:1s}{1:13.5f}".format(sResult, aSolution[i]) fL2Error += (aSolution[i] - aGlobal[i]) ** 2 fL2Error = np.sqrt(fL2Error) print("\nUsing the Gradient Descent algorithm on the SURROGATE objective function, the computed solution is:") print(" iterations: {0:14}".format(dInfo['performed_iterations'])) print(" computed: {0:1s}".format(sResult)) print(" L2 error: {0:14e}".format(fL2Error)) # Run the adaptive GD algorithm and check the output. Note that the adaptive stepsize in the state IS used here. state = Opt.GradientDescentState(x0, 1.0) dInfo = Opt.AdaptiveGradientDescent(func, grad, 1.25, 1.25, iNumIterations, fTolerance, state) aSolution = state.getX() sResult = "" fL2Error = 0.0 for i in range(2): sResult = "{0:1s}{1:13.5f}".format(sResult, aSolution[i]) fL2Error += (aSolution[i] - aGlobal[i]) ** 2 fL2Error = np.sqrt(fL2Error) print("\nUsing the ADAPTIVE Gradient Descent algorithm on the EXACT objective function, the computed solution is:") print(" iterations: {0:14}".format(dInfo['performed_iterations'])) print(" computed: {0:1s}".format(sResult)) print(" L2 error: {0:14e}".format(fL2Error)) # Run the projected adaptive GD algorithm and check the output. The domain constraint is implicitly enforced by the # projection function `proj`. state = Opt.GradientDescentState(x0, 1.0) proj = lambda x : np.array([min(0.5, max(0.0, x[0])), min(1.5, max(0.0, x[1]))]) # projection onto the box [0.0, 0.5] x [0.0, 1.5] dInfo = Opt.AdaptiveProjectedGradientDescent(func, grad, proj, 1.25, 1.25, iNumIterations, fTolerance, state) aGlobal = np.array([0.5, 1.5]) aSolution = state.getX() sResult = "" fL2Error = 0.0 for i in range(2): sResult = "{0:1s}{1:13.5f}".format(sResult, aSolution[i]) fL2Error += (aSolution[i] - aGlobal[i]) ** 2 fL2Error = np.sqrt(fL2Error) print("\nUsing the ADAPTIVE PROJECTED Gradient Descent algorithm on the EXACT objective function, the computed solution is:") print(" iterations: {0:14}".format(dInfo['performed_iterations'])) print(" computed: {0:1s}".format(sResult)) print(" L2 error: {0:14e}".format(fL2Error)) if __name__ == "__main__": example_02() TASMANIAN-8.1/InterfacePython/example_sparse_grids.in.py000077500000000000000000000075071470551176200232020ustar00rootroot00000000000000#!@Tasmanian_string_python_hashbang@ ############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## # The sys.path.append() command is necessary only if Tasmanian is # not included in the system PYTHONPATH # If PYTHONPATH is set (e.g., source TasmanianENVsetup.sh) you can jump # straight to import Tasmanian import sys @Tasmanian_python_example_import@ import Tasmanian import example_sparse_grids_01 import example_sparse_grids_02 import example_sparse_grids_03 import example_sparse_grids_04 import example_sparse_grids_05 import example_sparse_grids_06 import example_sparse_grids_07 import example_sparse_grids_08 import example_sparse_grids_09 import example_sparse_grids_10 import example_sparse_grids_11 if __name__ == "__main__": example_sparse_grids_01.example_01() example_sparse_grids_02.example_02() example_sparse_grids_03.example_03() example_sparse_grids_04.example_04() if len(sys.argv) < 2: # if running a long test example_sparse_grids_05.example_05() example_sparse_grids_06.example_06() example_sparse_grids_07.example_07() example_sparse_grids_08.example_08() example_sparse_grids_09.example_09() example_sparse_grids_10.example_10() example_sparse_grids_11.example_11() print("") TASMANIAN-8.1/InterfacePython/example_sparse_grids_01.py000066400000000000000000000102751470551176200230660ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_01(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 1: integrate f(x,y) = exp(-x^2) * cos(y),") print(" using clenshaw-curtis nodes and grid of type level") iNumDimensions = 2 iLevel = 5 fExactIntegral = 2.513723354063905e+00 # the exact integral grid = Tasmanian.SparseGrid() grid.makeGlobalGrid(iNumDimensions, 0, iLevel, "level", "clenshaw-curtis") aPoints = grid.getPoints() aWeights = grid.getQuadratureWeights() fApproximateIntegral = np.sum(aWeights * np.exp(-aPoints[:,0]**2) * np.cos(aPoints[:,1])) fError = np.abs(fApproximateIntegral - fExactIntegral) print(" at level: {0:1d}".format(iLevel)) print(" the grid has: {0:1d}".format(grid.getNumPoints())) print(" integral: {0:1.14e}".format(fApproximateIntegral)) print(" error: {0:1.14e}\n".format(fError)) iLevel = 7 grid.makeGlobalGrid(iNumDimensions, 0, iLevel, "level", "clenshaw-curtis") aPoints = grid.getPoints() aWeights = grid.getQuadratureWeights() fApproximateIntegral = np.sum(aWeights * np.exp(-aPoints[:,0]**2) * np.cos(aPoints[:,1])) fError = np.abs(fApproximateIntegral - fExactIntegral) print(" at level: {0:1d}".format(iLevel)) print(" the grid has: {0:1d}".format(grid.getNumPoints())) print(" integral: {0:1.14e}".format(fApproximateIntegral)) print(" error: {0:1.14e}\n".format(fError)) if (__name__ == "__main__"): example_01() TASMANIAN-8.1/InterfacePython/example_sparse_grids_02.py000066400000000000000000000111461470551176200230650ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_02(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 2: integrate f(x,y) = exp(-x^2) * cos(y) over [-5,5] x [-2,3]") print(" using Gauss-Patterson nodes and total degree polynomial space)") iNumDimensions = 2 iExactness = 20 fExactIntegral = 1.861816427518323e+00 # the type_qptotal will guarantee exact integral for all polynomials with degree 20 or less grid = Tasmanian.makeGlobalGrid(iNumDimensions, 0, iExactness, "qptotal", "gauss-patterson") grid.setDomainTransform(np.array([[-5.0, 5.0], [-2.0, 3.0]])) # set the non-canonical domain aPoints = grid.getPoints() aWeights = grid.getQuadratureWeights() fApproximateIntegral = np.sum(aWeights * np.exp(-aPoints[:,0]**2) * np.cos(aPoints[:,1])) fError = np.abs(fApproximateIntegral - fExactIntegral) print(" at polynomial exactness".format(iExactness)) print(" the grid has: {0:1d}".format(grid.getNumPoints())) print(" integral: {0:1.14e}".format(fApproximateIntegral)) print(" error: {0:1.14e}\n".format(fError)) iExactness = 40 # the type_qptotal will guarantee exact integral for all polynomials with degree 20 or less grid = Tasmanian.makeGlobalGrid(iNumDimensions, 0, iExactness, "qptotal", "gauss-patterson") grid.setDomainTransform(np.array([[-5.0, 5.0], [-2.0, 3.0]])) # must reset the domain aPoints = grid.getPoints() aWeights = grid.getQuadratureWeights() fApproximateIntegral = np.sum(aWeights * np.exp(-aPoints[:,0]**2) * np.cos(aPoints[:,1])) fError = np.abs(fApproximateIntegral - fExactIntegral) print(" at polynomial exactness".format(iExactness)) print(" the grid has: {0:1d}".format(grid.getNumPoints())) print(" integral: {0:1.14e}".format(fApproximateIntegral)) print(" error: {0:1.14e}\n".format(fError)) if (__name__ == "__main__"): example_02() TASMANIAN-8.1/InterfacePython/example_sparse_grids_03.py000066400000000000000000000107721470551176200230720ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_03(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 3: integrate exp(-x1^2 - x2^2) * cos(x3) * cos(x4)") print(" for x1, x2 in [-5,5]; x3, x4 in [-2,3]") print(" using different rules and total degree polynomial space\n") def make_grid(iPrecision, sRule): grid = Tasmanian.makeGlobalGrid(4, 0, iPrecision, "qptotal", sRule) grid.setDomainTransform(np.array([[-5.0, 5.0], [-5.0, 5.0], [-2.0, 3.0], [-2.0, 3.0]])) return grid def print_error(grid): fExactIntegral = 1.861816427518323e+00 * 1.861816427518323e+00 aPoints = grid.getPoints() aWeights = grid.getQuadratureWeights() fApproximateIntegral = np.sum(aWeights * np.exp(-aPoints[:,0]**2 -aPoints[:,1]**2) * np.cos(aPoints[:,2]) * np.cos(aPoints[:,3])) fError = np.abs(fApproximateIntegral - fExactIntegral) return "{0:>10d}{1:>10.2e}".format(grid.getNumPoints(), fError) print(" Clenshaw-Curtis Gauss-Legendre Gauss-Patterson") print(" precision points error points error points error") for prec in range(5, 41, 5): print("{0:>10d}{1:1s}{2:1s}{3:1s}".format( prec, print_error(make_grid(prec, "clenshaw-curtis")), print_error(make_grid(prec, "gauss-legendre-odd")), print_error(make_grid(prec, "gauss-patterson")))) print("\nAt 311K points the Gauss-Legendre error is O(1.E-1),") print(" Clenshaw-Curtis error is O(1.E-7) at 320K points.") print("At 70K points the Gauss-Patterson error is O(1.E-4),") print(" Clenshaw-Curtis needs 158K points to achieve the same.") if (__name__ == "__main__"): example_03() TASMANIAN-8.1/InterfacePython/example_sparse_grids_04.py000066400000000000000000000077461470551176200231020ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_04(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 4: interpolate f(x,y) = exp(-x^2) * cos(y), using clenshaw-curtis iptotal rule") iNumInputs = 2 iNumOutputs = 1 aPointOfInterest = np.array([0.3, 0.7]) aReferenceSolution = np.exp(-aPointOfInterest[0]**2) * np.cos(aPointOfInterest[1]) for prec in [6, 12]: grid = Tasmanian.makeGlobalGrid(iNumInputs, iNumOutputs, prec, "iptotal", "clenshaw-curtis") aPoints = grid.getNeededPoints() aModelValues = np.exp(-aPoints[:,0]**2) * np.cos(aPoints[:,1]) grid.loadNeededValues(aModelValues.reshape((aModelValues.shape[0], iNumOutputs))) # when using multiple points at once, evaluateBatch() is more efficient aResult = grid.evaluate(aPointOfInterest) fError = np.abs(aResult[0] - aReferenceSolution) print("\n using total degree polynomials: {0:>2d}th degree".format(prec)) print(" the grid has: {0:1d} points".format(grid.getNumPoints())) print(" interpolant at (0.3,0.7): {0:1.5e}".format(aResult[0])) print(" error: {0:1.5e}".format(fError)) if (__name__ == "__main__"): example_04() TASMANIAN-8.1/InterfacePython/example_sparse_grids_05.py000066400000000000000000000151221470551176200230660ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_05(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 5: interpolate f(x,y) = exp(-x^2) * cos(y), using leja rule") print(" employ adaptive refinement to increase accuracy per samples") iNumInputs = 2 iNumOutputs = 1 def model(aX): return np.ones((1,)) * np.exp(-aX[0] * aX[0]) * np.cos(aX[1]) iTestGridSize = 33 dx = np.linspace(-1.0, 1.0, iTestGridSize) # sample on a uniform grid aMeshX, aMeshY = np.meshgrid(dx, dx) aTestPoints = np.column_stack([aMeshX.reshape((iTestGridSize**2, 1)), aMeshY.reshape((iTestGridSize**2, 1))]) aReferenceValues = np.exp(-aTestPoints[:,0]**2) * np.cos(aTestPoints[:,1]) aReferenceValues = aReferenceValues.reshape((aReferenceValues.shape[0], 1)) def testGrid(grid, aTestPoints, aReferenceValues): aResult = grid.evaluateBatch(aTestPoints) for i in range(20): aX = aTestPoints[i,:] return np.max(np.abs(aResult - aReferenceValues)) iInitialLevel = 5 grid_isotropic = Tasmanian.SparseGrid() grid_iptotal = Tasmanian.SparseGrid() grid_icurved = Tasmanian.SparseGrid() grid_surplus = Tasmanian.SparseGrid() grid_isotropic.makeGlobalGrid(iNumInputs, iNumOutputs, iInitialLevel, "level", "leja") grid_iptotal.copyGrid(grid_isotropic) grid_icurved.copyGrid(grid_isotropic) grid_surplus.copyGrid(grid_isotropic) iNumThreads = 1 iBudget = 100 print("{0:>22s}{1:>22s}{2:>22s}{3:>22s}".format("isotropic", "iptotal", "ipcurved", "surplus")) print("{0:>8s}{1:>14s}{0:>8s}{1:>14s}{0:>8s}{1:>14s}{0:>8s}{1:>14s}".format("points", "error")) bBelowBudget = True while(bBelowBudget): sInfo = "" if (grid_isotropic.getNumLoaded() < iBudget): Tasmanian.loadNeededValues(lambda x, tid : model(x), grid_isotropic, iNumThreads) sInfo += "{0:>8d}{1:>14s}".format(grid_isotropic.getNumLoaded(), "{0:1.4e}".format(testGrid(grid_isotropic, aTestPoints, aReferenceValues))) iLevel = 0 while(grid_isotropic.getNumNeeded() == 0): grid_isotropic.updateGlobalGrid(iLevel, "level") iLevel += 1 else: sInfo += "{0:>22s}".format("") if (grid_iptotal.getNumLoaded() < iBudget): Tasmanian.loadNeededValues(lambda x, tid : model(x), grid_iptotal, iNumThreads) sInfo += "{0:>8d}{1:>14s}".format(grid_iptotal.getNumLoaded(), "{0:1.4e}".format(testGrid(grid_iptotal, aTestPoints, aReferenceValues))) grid_iptotal.setAnisotropicRefinement("iptotal", 10, 0); else: sInfo += "{0:>22s}".format("") if (grid_icurved.getNumLoaded() < iBudget): Tasmanian.loadNeededValues(lambda x, tid : model(x), grid_icurved, iNumThreads) sInfo += "{0:>8d}{1:>14s}".format(grid_icurved.getNumLoaded(), "{0:1.4e}".format(testGrid(grid_icurved, aTestPoints, aReferenceValues))) grid_icurved.setAnisotropicRefinement("ipcurved", 10, 0); else: sInfo += "{0:>22s}".format("") if (grid_surplus.getNumLoaded() < iBudget): Tasmanian.loadNeededValues(lambda x, tid : model(x), grid_surplus, iNumThreads) sInfo += "{0:>8d}{1:>14s}".format(grid_surplus.getNumLoaded(), "{0:1.4e}".format(testGrid(grid_surplus, aTestPoints, aReferenceValues))) grid_surplus.setSurplusRefinement(1.E-8, 0) else: sInfo += "{0:>22s}".format("") print(sInfo) bBelowBudget = (grid_isotropic.getNumLoaded() < iBudget or grid_icurved.getNumLoaded() < iBudget or grid_icurved.getNumLoaded() < iBudget or grid_surplus.getNumLoaded() < iBudget) if (__name__ == "__main__"): example_05() TASMANIAN-8.1/InterfacePython/example_sparse_grids_06.py000066400000000000000000000110161470551176200230650ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_06(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 6: interpolate f(x,y) = exp(-5 * x^2) * cos(z), using the rleja rule") print(" employs adaptive construction\n") iNumInputs = 2 iNumOutputs = 1 iNumSamplesPerBatch = 1 # the model is set for a single sample per-batch def model(aX): # note that the model has to return a 2-D numpy.ndarray return np.ones((1,1)) * np.exp(-5.0 * aX[0, 0] ** 2.0) * np.cos(aX[0, 1]) iTestGridSize = 33 dx = np.linspace(-1.0, 1.0, iTestGridSize) # sample on a uniform grid aMeshX, aMeshY = np.meshgrid(dx, dx) aTestPoints = np.column_stack([aMeshX.reshape((iTestGridSize**2, 1)), aMeshY.reshape((iTestGridSize**2, 1))]) aReferenceValues = np.exp(-5.0 * aTestPoints[:,0]**2) * np.cos(aTestPoints[:,1]) aReferenceValues = aReferenceValues.reshape((aReferenceValues.shape[0], 1)) def testGrid(grid, aTestPoints, aReferenceValues): aResult = grid.evaluateBatch(aTestPoints) for i in range(20): aX = aTestPoints[i,:] return np.max(np.abs(aResult - aReferenceValues)) grid = Tasmanian.SparseGrid() grid.makeSequenceGrid(iNumInputs, iNumOutputs, 2, "level", "rleja") iNumThreads = 1 print("{0:>8s}{1:>14s}".format("points", "error")) for i in range(4): iBudget = 50 * (i + 1) Tasmanian.constructAnisotropicSurrogate(lambda x, tid : model(x), iBudget, iNumThreads, iNumSamplesPerBatch, grid, "iptotal", 0) print("{0:>8d}{1:>14s}".format(grid.getNumPoints(), "{0:1.4e}".format(testGrid(grid, aTestPoints, aReferenceValues)))) if (__name__ == "__main__"): example_06() TASMANIAN-8.1/InterfacePython/example_sparse_grids_07.py000066400000000000000000000060141470551176200230700ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_07(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 7: the C++ example runs a benchmark between global and sequence grids") print(" no need to repeat the example in Python the numbers will not differ") if (__name__ == "__main__"): example_07() TASMANIAN-8.1/InterfacePython/example_sparse_grids_08.py000066400000000000000000000126561470551176200231020ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_08(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 8: interpolate different functions demonstrating the different") print(" local polynomial rules\n") iNumInputs = 2 # using two inputs for testing # test the error on a uniform dense grid with 10K points iTestGridSize = 100 dx = np.linspace(-1.0, 1.0, iTestGridSize) # sample on a uniform grid aMeshX, aMeshY = np.meshgrid(dx, dx) aTestPoints = np.column_stack([aMeshX.reshape((iTestGridSize**2, 1)), aMeshY.reshape((iTestGridSize**2, 1))]) def get_error(grid, model, aTestPoints): aGridResult = grid.evaluateBatch(aTestPoints) aModelResult = np.empty((aTestPoints.shape[0], 1), np.float64) for i in range(aTestPoints.shape[0]): aModelResult[i,:] = model(aTestPoints[i,:]) return np.max(np.abs(aModelResult[:,0] - aGridResult[:,0])) def smooth_model(aX): return np.ones((1,)) * np.exp(-aX[0]**2) * np.cos(aX[1]) iOrder = 2 grid_localp = Tasmanian.makeLocalPolynomialGrid(iNumInputs, 1, 7, iOrder, "localp") grid_semilocalp = Tasmanian.makeLocalPolynomialGrid(iNumInputs, 1, 7, iOrder, "semi-localp") Tasmanian.loadNeededValues(lambda x, tid : smooth_model(x), grid_localp, 4) Tasmanian.loadNeededValues(lambda x, tid : smooth_model(x), grid_semilocalp, 4) print("Using smooth model: f(x, y) = exp(-x*x) * cos(y)") print(" rule_localp, points = {0:1d} error = {1:1.4e}".format( grid_localp.getNumPoints(), get_error(grid_localp, smooth_model, aTestPoints))) print(" rule_semilocalp, points = {0:1d} error = {1:1.4e}".format( grid_semilocalp.getNumPoints(), get_error(grid_semilocalp, smooth_model, aTestPoints))) print(" If the model is smooth, rule_semilocalp has an advantage.\n") def zero_model(aX): return np.ones((1,)) * np.cos(0.5 * np.pi * aX[0]) * np.cos(0.5 * np.pi * aX[1]) grid_localp0 = Tasmanian.makeLocalPolynomialGrid(iNumInputs, 1, 6, iOrder, "localp-zero") Tasmanian.reloadLoadedPoints(lambda x, tid : zero_model(x), grid_localp, 4) Tasmanian.loadNeededValues(lambda x, tid : zero_model(x), grid_localp0, 4) print("Using homogeneous model: f(x, y) = cos(pi * x / 2) * cos(pi * y / 2)") print(" rule_localp, points = {0:1d} error = {1:1.4e}".format( grid_localp.getNumPoints(), get_error(grid_localp, zero_model, aTestPoints))) print(" rule_localp0, points = {0:1d} error = {1:1.4e}".format( grid_localp0.getNumPoints(), get_error(grid_localp0, zero_model, aTestPoints))) print(" The rule_localp0 uses basis tuned for models with zero boundary.") if (__name__ == "__main__"): example_08() TASMANIAN-8.1/InterfacePython/example_sparse_grids_09.py000066400000000000000000000135341470551176200230770ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_09(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 9: comparison between local polynomial refinement strategies\n") iNumInputs = 2 # using two inputs for testing # test the error on a uniform dense grid with 10K points iTestGridSize = 100 dx = np.linspace(-1.0, 1.0, iTestGridSize) # sample on a uniform grid aMeshX, aMeshY = np.meshgrid(dx, dx) aTestPoints = np.column_stack([aMeshX.reshape((iTestGridSize**2, 1)), aMeshY.reshape((iTestGridSize**2, 1))]) def get_error(grid, model, aTestPoints): aGridResult = grid.evaluateBatch(aTestPoints) aModelResult = np.empty((aTestPoints.shape[0], 1), np.float64) for i in range(aTestPoints.shape[0]): aModelResult[i,:] = model(aTestPoints[i,:]) return np.max(np.abs(aModelResult[:,0] - aGridResult[:,0])) def sharp_model(aX): return np.ones((1,)) * np.exp(-aX[0]) / (1.0 + 100.0 * np.exp(-10.0 * aX[1])) grid_classic = Tasmanian.makeLocalPolynomialGrid(iNumInputs, 1, 2, iOrder = -1, sRule = "localp") grid_fds = Tasmanian.copyGrid(grid_classic) print("Using batch refinement:") print(" classic fds") print(" points error points error") fTolerance = 1.E-5; while((grid_classic.getNumNeeded() > 0) or (grid_fds.getNumNeeded() > 0)): Tasmanian.loadNeededValues(lambda x, tid: sharp_model(x), grid_classic, 4); Tasmanian.loadNeededValues(lambda x, tid: sharp_model(x), grid_fds, 4); # print the results at this stage print("{0:>8d}{1:>14.4e}{2:>8d}{3:>14.4e}".format( grid_classic.getNumLoaded(), get_error(grid_classic, sharp_model, aTestPoints), grid_fds.getNumLoaded(), get_error(grid_fds, sharp_model, aTestPoints))) # setting refinement for each grid grid_classic.setSurplusRefinement(fTolerance, 0, "classic"); grid_fds.setSurplusRefinement(fTolerance, 0, "fds"); # reset the grid and repeat using construction grid_classic = Tasmanian.makeLocalPolynomialGrid(iNumInputs, 1, 2, iOrder = -1, sRule = "localp") grid_fds.copyGrid(grid_classic) print("\nUsing construction:") print(" classic fds") print(" points error points error") iNumThreads = 1 for budget in range(50, 800, 100): Tasmanian.constructSurplusSurrogate( lambda x, tid : sharp_model(x.reshape((2,))).reshape((1,1)), budget, iNumThreads, 1, grid_classic, fTolerance, "classic") Tasmanian.constructSurplusSurrogate( lambda x, tid : sharp_model(x.reshape((2,))).reshape((1,1)), budget, iNumThreads, 1, grid_fds, fTolerance, "fds") print("{0:>8d}{1:>14.4e}{2:>8d}{3:>14.4e}".format( grid_classic.getNumLoaded(), get_error(grid_classic, sharp_model, aTestPoints), grid_fds.getNumLoaded(), get_error(grid_fds, sharp_model, aTestPoints))) if (__name__ == "__main__"): example_09() TASMANIAN-8.1/InterfacePython/example_sparse_grids_10.py000066400000000000000000000114221470551176200230610ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np import Tasmanian def example_10(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 10: comparison between local polynomial and wavelet grids\n") iNumInputs = 2 # using two inputs for testing # test the error on a uniform dense grid with 10K points iTestGridSize = 100 dx = np.linspace(-1.0, 1.0, iTestGridSize) # sample on a uniform grid aMeshX, aMeshY = np.meshgrid(dx, dx) aTestPoints = np.column_stack([aMeshX.reshape((iTestGridSize**2, 1)), aMeshY.reshape((iTestGridSize**2, 1))]) def get_error(grid, model, aTestPoints): aGridResult = grid.evaluateBatch(aTestPoints) aModelResult = np.empty((aTestPoints.shape[0], 1), np.float64) for i in range(aTestPoints.shape[0]): aModelResult[i,:] = model(aTestPoints[i,:]) return np.max(np.abs(aModelResult[:,0] - aGridResult[:,0])) def sharp_model(aX): return np.ones((1,)) * aX[0] / (1.0 + 100.0 * np.exp(-10.0 * aX[1])) grid_poly = Tasmanian.makeLocalPolynomialGrid(iNumInputs, 1, 3, iOrder = 1, sRule = "localp") grid_wavelet = Tasmanian.makeWaveletGrid(iNumInputs, 1, 1, 1) print(" polynomial wavelet") print(" points error points error") fTolerance = 1.E-5; while((grid_poly.getNumNeeded() > 0) or (grid_wavelet.getNumNeeded() > 0)): Tasmanian.loadNeededValues(lambda x, tid: sharp_model(x), grid_poly, 4); Tasmanian.loadNeededValues(lambda x, tid: sharp_model(x), grid_wavelet, 4); # print the results at this stage print("{0:>8d}{1:>14.4e}{2:>8d}{3:>14.4e}".format( grid_poly.getNumLoaded(), get_error(grid_poly, sharp_model, aTestPoints), grid_wavelet.getNumLoaded(), get_error(grid_wavelet, sharp_model, aTestPoints))) # setting refinement for each grid grid_poly.setSurplusRefinement(fTolerance, 0, "fds"); grid_wavelet.setSurplusRefinement(fTolerance, 0, "fds"); if (__name__ == "__main__"): example_10() TASMANIAN-8.1/InterfacePython/example_sparse_grids_11.py000066400000000000000000000113731470551176200230670ustar00rootroot00000000000000############################################################################################################################################################################## # Copyright (c) 2017, Miroslav Stoyanov # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. # THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, # COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. # THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, # IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. ############################################################################################################################################################################## import numpy as np from random import uniform import Tasmanian def example_11(): print("\n---------------------------------------------------------------------------------------------------\n") print("Example 11: Using unstructured data\n") iNumInputs = 2 # using two inputs for testing # test the error on a uniform dense grid with 10K points iTestGridSize = 100 dx = np.linspace(-1.0, 1.0, iTestGridSize) # sample on a uniform grid aMeshX, aMeshY = np.meshgrid(dx, dx) aTestPoints = np.column_stack([aMeshX.reshape((iTestGridSize**2, 1)), aMeshY.reshape((iTestGridSize**2, 1))]) def get_error(grid, model, aTestPoints): aGridResult = grid.evaluateBatch(aTestPoints) aModelResult = np.empty((aTestPoints.shape[0], 1), np.float64) for i in range(aTestPoints.shape[0]): aModelResult[i,:] = model(aTestPoints[i,:]) return np.max(np.abs(aModelResult[:,0] - aGridResult[:,0])) def model(aX): return np.ones((1,)) * np.exp( - aX[0]**2 - aX[1]**2 ) grid = Tasmanian.makeGlobalGrid(iNumInputs, 1, 4, "level", "clenshaw-curtis") # generate random data iNumData = 2000 inputs = np.zeros((iNumData, iNumInputs)) outputs = np.zeros((iNumData, 1)) for i in range(iNumData): inputs[i,0] = uniform(-1.0, 1.0) inputs[i,1] = uniform(-1.0, 1.0) outputs[i,:] = model(inputs[i,:]) if (not grid.isAccelerationAvailable("cpu-blas") and not grid.isAccelerationAvailable("gpu-cuda") and not grid.isAccelerationAvailable("gpu-magma")): print("Skipping example 11, BLAS, CUDA, or MAGMA acceleration required.") return Tasmanian.loadUnstructuredDataL2(inputs, outputs, 1.E-4, grid) print("Using construction from unstructured (random) data") print(" approximatino error = {0:1.6E}".format(get_error(grid, model, aTestPoints))) print(" note: compared to the C++ code, this example does not fix the random seed") print(" the error will be slightly different every time you run the example") print("") if (__name__ == "__main__"): example_11() TASMANIAN-8.1/InterfacePython/sandbox.py000077500000000000000000000014341470551176200200240ustar00rootroot00000000000000#!@Tasmanian_string_python_hashbang@ # necessary import for every use of TASMANIAN # import Tasmanian import numpy as np import math #from random import uniform #import matplotlib.pyplot as plt #import matplotlib.colors as cols #from mpl_toolkits.mplot3d import Axes3D ############################################################################### # This file is included for testing, debugging and development reasons # This file will reside in the cmake build folder, but not the install folder # Basically, add testing code to this file and it will be automatically # included as part of the cmake # You can also use the file without cmake ############################################################################### print("Add code to this file to test, debug, or develop features") TASMANIAN-8.1/InterfacePython/testAcceleration.py000066400000000000000000000156761470551176200216710ustar00rootroot00000000000000import unittest import TasmanianSG import sys, os import numpy as np from random import uniform import testConfigureData as tdata # needed to keep track of configured acceleration methods import testCommon ttc = testCommon.TestTasCommon() class TestTasClass(unittest.TestCase): ''' Test the acceleration options: * consistency between CMake options and options reported by C++/Python * ability to switch between GPUs, read properties set GPUID, etc. * consistency between accelerated and reference evaluations ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def checkMeta(self): ''' Check if the CMake options are propagated to the C++ library and the correct acceleration options are passed between C++ and Python. ''' grid = TasmanianSG.TasmanianSparseGrid() if (tdata.bEnableSyncTests): self.assertTrue((grid.isAccelerationAvailable("cpu-blas") == tdata.bHasBlas), "failed to match blas") self.assertTrue((grid.isAccelerationAvailable("gpu-cublas") == tdata.bHasCuBlas), "failed to match cublas") self.assertTrue((grid.isAccelerationAvailable("gpu-cuda") == tdata.bHasCuda), "failed to match cuda") self.assertTrue((grid.isAccelerationAvailable("gpu-default") == (tdata.bHasCuBlas or tdata.bHasCuda)), "failed to match cuda") # acceleration meta-data lsAvailableAcc = [] if (tdata.bHasBlas): lsAvailableAcc.append("cpu-blas") if (tdata.bHasCuBlas): lsAvailableAcc.append("gpu-cublas") if (tdata.bHasCuda): lsAvailableAcc.append("gpu-cuda") grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'semi-localp') for accel in lsAvailableAcc: grid.enableAcceleration(accel) sA = grid.getAccelerationType() bTest = ((accel not in sA) or (sA not in accel)) self.assertFalse(bTest, "set/get Acceleration") lsAvailableAcc = [] if (tdata.bHasCuBlas): lsAvailableAcc.append(("gpu-rocblas", "gpu-cublas")) if (tdata.bHasCuda): lsAvailableAcc.append(("gpu-hip", "gpu-cuda")) for accel in lsAvailableAcc: grid.enableAcceleration(accel[0]) sA = grid.getAccelerationType() bTest = ((accel[1] not in sA) or (sA not in accel[1])) self.assertFalse(bTest, "set/get Acceleration with HIP - CUDA aliases") def checkMultiGPU(self): ''' Check setting and resetting the GPU ID and reading the device names. ''' grid = TasmanianSG.TasmanianSparseGrid() if (tdata.bHasSycl): self.assertTrue((grid.getGPUID() == -1), "did not default to gpu -1 (default_selector") else: self.assertTrue((grid.getGPUID() == 0), "did not default to gpu 0") if (grid.getNumGPUs() > 1): grid.setGPUID(1) self.assertTrue((grid.getGPUID() == 1), "did not set to gpu 1") if (not tdata.bUsingMSVC): sName = grid.getGPUName(1) # mostly checks for memory leaks and crashes if (grid.getNumGPUs() > 0): grid.setGPUID(0) self.assertTrue((grid.getGPUID() == 0), "did not set to gpu 0") if (not tdata.bUsingMSVC): sName = grid.getGPUName(0) # mostly checks for memory leaks and crashes def checkEvaluateConsistency(self): ''' Check for consistency between accelerated and reference evaluations. In short, set a grid, load points, evaluate in different ways. Test all visible GPUs and combinations cuBlas/MAGMA, etc. ''' grid = TasmanianSG.TasmanianSparseGrid() aTestPointsCanonical = np.array([[ uniform(-1.0, 1.0) for j in range(2) ] for i in range(100) ]) aTestPointsTransformed = np.array([[ uniform(3.0, 5.0) for j in range(2) ] for i in range(100) ]) aDomainTransform = np.array([[3.0, 5.0],[3.0, 5.0]]) iFastEvalSubtest = 6 lTests = [ 'grid.makeGlobalGrid(2, 2, 4, "level", "clenshaw-curtis")', 'grid.makeGlobalGrid(2, 2, 4, "level", "chebyshev")', 'grid.makeSequenceGrid(2, 2, 4, "level", "leja")', 'grid.makeLocalPolynomialGrid(2, 3, 4, 1, "localp")', 'grid.makeLocalPolynomialGrid(2, 2, 4, 2, "localp")', 'grid.makeLocalPolynomialGrid(2, 1, 4, 3, "localp")', 'grid.makeLocalPolynomialGrid(2, 1, 4, 4, "semi-localp")', 'grid.makeWaveletGrid(2, 1, 3, 1)', 'grid.makeWaveletGrid(2, 1, 3, 3)', 'grid.makeFourierGrid(2, 1, 3, "level")' ] iNumGPUs = grid.getNumGPUs() lsAccelTypes = ["none", "cpu-blas", "gpu-cuda", "gpu-cublas", "gpu-magma"] for sTest in lTests: for iI in range(2): iC = 0 iGPU = 0 if (tdata.iGPUID > -1): iGPU = tdata.iGPUID while (iC < len(lsAccelTypes)): sAcc = lsAccelTypes[iC] exec(sTest) if (iI == 0): aTestPoints = aTestPointsCanonical else: aTestPoints = aTestPointsTransformed grid.setDomainTransform(aDomainTransform) grid.enableAcceleration(sAcc) if ((sAcc == "gpu-cuda") or (sAcc == "gpu-cublas") or (sAcc == "gpu-magma")): if (iGPU < grid.getNumGPUs()): # without cuda or cublas, NumGPUs is 0 and cannot set GPU grid.setGPUID(iGPU) ttc.loadExpN2(grid) aRegular = np.array([grid.evaluateThreadSafe(aTestPoints[i,:]) for i in range(aTestPoints.shape[0]) ]) aBatched = grid.evaluateBatch(aTestPoints) np.testing.assert_almost_equal(aRegular, aBatched, 14, "Batch evaluation test not equal: {0:1s}, acceleration: {1:1s}, gpu: {2:1d}".format(sTest, sAcc, iGPU), True) aFast = np.array([ grid.evaluate(aTestPoints[i,:]) for i in range(iFastEvalSubtest) ]) np.testing.assert_almost_equal(aRegular[0:iFastEvalSubtest,:], aFast, 14, "Batch evaluation test not equal: {0:1s}, acceleration: {1:1s}, gpu: {2:1d}".format(sTest, sAcc, iGPU), True) if ((sAcc == "gpu-cuda") or (sAcc == "gpu-cublas") or (sAcc == "gpu-magma")): if (tdata.iGPUID == -1): iGPU += 1 if (iGPU >= iNumGPUs): iC += 1 iGPU = 0 else: iC += 1 else: iC += 1 def performAccelerationTest(self): self.checkMeta() self.checkMultiGPU() self.checkEvaluateConsistency() TASMANIAN-8.1/InterfacePython/testAddons.py000066400000000000000000000226041470551176200204750ustar00rootroot00000000000000import unittest import Tasmanian import os import numpy as np import testCommon ttc = testCommon.TestTasCommon() def batch_exp(x): aResult = np.zeros((x.shape[0], 1)) for i in range(x.shape[0]): aResult[i, 0] = np.exp(-np.sum(x[i,:])) return aResult class TestTasClass(unittest.TestCase): ''' Miscelaneous tests that don't quite fit in other categories. ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def checkLoadNeeded(self): ''' Check the load needed construction procedure. ''' gridA = Tasmanian.SparseGrid() gridB = Tasmanian.SparseGrid() for i in range(4): if i < 2: gridA.makeGlobalGrid(2, 1, 3, 'level', 'fejer2') gridB.copyGrid(gridA) Tasmanian.loadNeededValues(lambda x, i : np.ones((1,)) * np.exp(-np.sum(x**2)), gridA, i) else: gridA.makeLocalPolynomialGrid(2, 1, 2, 2) gridB.copyGrid(gridA) gridA.printStats() gridA.loadNeededPoints(np.ones((gridA.getNumPoints(), 1))) Tasmanian.reloadLoadedPoints(lambda x, i : np.ones((1,)) * np.exp(-np.sum(x**2)), gridA, i - 2) ttc.loadExpN2(gridB) ttc.compareGrids(gridA, gridB) def checkConstruction(self): gridA = Tasmanian.SparseGrid() gridB = Tasmanian.SparseGrid() for i in range(12): if i < 2: gridA.makeGlobalGrid(2, 1, 3, 'level', 'fejer2') gridB.copyGrid(gridA) Tasmanian.constructAnisotropicSurrogate(lambda x, i : np.ones((1,1)) * np.exp(-np.sum(x**2)), gridA.getNumPoints(), i, 1, gridA, "hyperbolic", 0) elif i < 4: gridA.makeGlobalGrid(2, 1, 3, 'level', 'min-lebesgue') gridB.copyGrid(gridA) Tasmanian.constructAnisotropicSurrogate(lambda x, y, i : np.ones((1,1)) * np.exp(-np.sum(x**2)), gridA.getNumPoints(), i - 2, 1, gridA, "ipcurved", (6, 5, 1, 1), bUseInitialGuess = True, sCheckpointFilename = "cpf_addons") os.remove("cpf_addons") elif i < 6: gridA.makeGlobalGrid(2, 1, 3, 'level', 'min-delta', liLevelLimits = (5, 5)) gridB.copyGrid(gridA) gridA.clearLevelLimits() Tasmanian.constructAnisotropicSurrogate(lambda x, i : np.ones((1,1)) * np.exp(-np.sum(x**2)), gridA.getNumPoints(), i - 4, 1, gridA, "iplevel", (1, 2), liLevelLimits = (5, 5), bUseInitialGuess = False) elif i < 8: gridA.makeGlobalGrid(2, 1, 3, 'level', 'min-delta', liLevelLimits = (10, 10)) gridB.copyGrid(gridA) gridA.clearLevelLimits() Tasmanian.constructAnisotropicSurrogate(lambda x, y, i : np.ones((1,1)) * np.exp(-np.sum(x**2)), gridA.getNumPoints(), i - 6, 1, gridA, "iplevel", 0, liLevelLimits = (10, 10), bUseInitialGuess = True) elif i < 10: gridA.makeLocalPolynomialGrid(2, 1, 2, 2, liLevelLimits = (7, 7)) gridB.copyGrid(gridA) gridA.clearLevelLimits() Tasmanian.constructSurplusSurrogate(lambda x, y, i : np.ones((1,1)) * np.exp(-np.sum(x**2)), gridA.getNumPoints(), i - 8, 1, gridA, 1.E-5, "stable", -1, liLevelLimits = (7, 7), bUseInitialGuess = True) elif i < 12: gridA.makeLocalPolynomialGrid(2, 1, 2, 3) gridB.copyGrid(gridA) Tasmanian.constructSurplusSurrogate(lambda x, i : np.ones((1,1)) * np.exp(-np.sum(x**2)), gridA.getNumPoints(), i - 10, 1, gridA, 1.E-5, "fds", 0, bUseInitialGuess = False, sCheckpointFilename = "cpf_addons") os.remove("cpf_addons") ttc.loadExpN2(gridB) gridA.finishConstruction() ttc.compareGrids(gridA, gridB) def checkBatchConstruct(self): gridA = Tasmanian.SparseGrid() gridB = Tasmanian.SparseGrid() gridA.makeGlobalGrid(2, 1, 6, 'level', 'fejer2') gridB.copyGrid(gridA) Tasmanian.constructAnisotropicSurrogate(lambda x, i : batch_exp(x), gridA.getNumPoints(), 2, 1, gridA, "iptotal", 0) Tasmanian.constructAnisotropicSurrogate(lambda x, i : batch_exp(x), gridB.getNumPoints(), 2, 10, gridB, "iptotal", 0) ttc.compareGrids(gridA, gridB) gridA.makeLocalPolynomialGrid(2, 1, 3) gridB.copyGrid(gridA) Tasmanian.constructSurplusSurrogate(lambda x, i : batch_exp(x), gridA.getNumPoints(), 2, 1, gridA, 1.E-11, "classic") Tasmanian.constructSurplusSurrogate(lambda x, i : batch_exp(x), gridB.getNumPoints(), 2, 10, gridB, 1.E-11, "classic") ttc.compareGrids(gridA, gridB) def checkUnstructuredL2(self): grid = Tasmanian.makeLocalPolynomialGrid(2, 1, 5) if not grid.isAccelerationAvailable("cpu-blas"): return x = np.linspace(-0.9, 0.9, 40) xx, yy = np.meshgrid(x, x) points = np.column_stack([xx.reshape((xx.size,)), yy.reshape((yy.size,))]) model = np.exp(points[:,0] - points[:,1]).reshape((points.shape[0], 1)) Tasmanian.loadUnstructuredDataL2(points, model, 1.E-5, grid) x = np.linspace(-0.8, 0.8, 20) xx, yy = np.meshgrid(x, x) points = np.column_stack([xx.reshape((xx.size,)), yy.reshape((yy.size,))]) model = np.exp(points[:,0] - points[:,1]) surrogate = grid.evaluateBatch(points) self.assertLess(np.max(np.abs(model - surrogate[:,0])), 5.E-3, "Constructed from unstructured too inaccurate.") def checkExoticQuadrature(self): # Initialize some useful constants and utility functions. integrand = lambda x : np.exp(-np.linalg.norm(x) ** 2) sinc1s0 = lambda x : np.sinc(x / np.pi) sinc10s1 = lambda x : np.sinc(10 * (x - 1) / np.pi) max_level = 25 nref = 101 def create_surrogate(lambda_fn): grid = Tasmanian.makeGlobalGrid(1, 1, nref, "level", "gauss-legendre") grid.loadNeededValues(np.apply_along_axis(lambda_fn, 1, grid.getNeededPoints())) return grid def compute_integral(grid, integrand): return np.sum(np.apply_along_axis(integrand, 1, grid.getPoints()) * grid.getQuadratureWeights()) # Each pair below consists of a 1D integral value (first) and a CustomTabulated object (second) used to approximate this integral. testPairs = [ [1.4321357541271255E-00, Tasmanian.createExoticQuadratureFromFunction(max_level, 0.0, sinc1s0, nref, "Sinc1s0-shift0-Symm-byFn", True)], [1.4321357541271255E-00, Tasmanian.createExoticQuadratureFromFunction(max_level, 0.0, sinc1s0, nref, "Sinc1s0-shift0-nonSymm-byFn", False)], [1.4321357541271255E-00, Tasmanian.createExoticQuadratureFromFunction(max_level, 1.0, sinc1s0, nref, "Sinc1s0-shift1-Symm-byFn", True)], [6.4062055930705356E-02, Tasmanian.createExoticQuadratureFromFunction(max_level, 1.0, sinc10s1, nref, "Sinc10s1-shift1-nonSymm-byFn", False)], [1.4321357541271255E-00, Tasmanian.createExoticQuadratureFromGrid(max_level, 0.0, create_surrogate(sinc1s0), "Sinc1s0-shift0-Symm-byGrid", True)], [1.4321357541271255E-00, Tasmanian.createExoticQuadratureFromGrid(max_level, 0.0, create_surrogate(sinc1s0), "Sinc1s0-shift0-nonSymm-byGrid", False)], [1.4321357541271255E-00, Tasmanian.createExoticQuadratureFromGrid(max_level, 1.0, create_surrogate(sinc1s0), "Sinc1s0-shift1-Symm-byGrid", True)], [6.4062055930705356E-02, Tasmanian.createExoticQuadratureFromGrid(max_level, 1.0, create_surrogate(sinc10s1), "Sinc10s1-shift1-nonSymm-byGrid", False)], ] # Test the accuracy of exotic quadrature. for integral, ct in testPairs: self.assertEqual(max_level, ct.getNumLevels(), "Loaded number of levels does not match actual number of levels!") grid = Tasmanian.makeGlobalGridCustom(1, 0, max_level-1, "level", ct) np.testing.assert_almost_equal(compute_integral(grid, integrand), integral, 10, "Computed integral does not match exact integral in test instance " + ct.getDescription()) grid.makeGlobalGridCustom(2, 0, max_level-1, "level", ct) np.testing.assert_almost_equal(compute_integral(grid, integrand), integral ** 2, 10, "Computed integral does not match exact integral in test instance " + ct.getDescription()) def performAddonTests(self): self.checkLoadNeeded() self.checkConstruction() self.checkBatchConstruct() self.checkUnstructuredL2() self.checkExoticQuadrature() TASMANIAN-8.1/InterfacePython/testBasicIO.py000066400000000000000000000520101470551176200205300ustar00rootroot00000000000000import unittest import TasmanianSG import sys, os import numpy as np import testConfigureData as tdata # needed for Gauss-Patterson table file import testCommon ttc = testCommon.TestTasCommon() class TestTasClass(unittest.TestCase): ''' Test the read/write functionality in different formats, also the reading of various meta-data (i.e., version or gpu info) ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def checkMetaIO(self): ''' Test the version I/O, available acceleration, gpu info, print stats ''' grid = TasmanianSG.TasmanianSparseGrid() print("Tasmanian Sparse Grids version: {0:1s}".format(grid.getVersion())) print(" version major: {0:1d}".format(grid.getVersionMajor())) print(" version minor: {0:1d}".format(grid.getVersionMinor())) print(" License: {0:1s}".format(grid.getLicense())) if (grid.isOpenMPEnabled()): sStatus = "Enabled" else: sStatus = "Disabled" print(" OpenMP: {0:1s}".format(sStatus)) sAvailableAcceleration = "" sGPUbackend = "none" if (grid.isCudaEnabled()): sGPUbackend = "CUDA" if (grid.isHipEnabled()): sGPUbackend = "ROCm/HIP" if (grid.isDpcppEnabled()): sGPUbackend = "oneAPI/DPC++" print(" GPU backend: {0:1s}".format(sGPUbackend)) for s in ["cpu-blas", "gpu-cublas", "gpu-cuda", "gpu-magma"]: if (grid.isAccelerationAvailable(s)): sAvailableAcceleration += " " + s print(" Available acceleration:{0:1s}".format(sAvailableAcceleration)) print(" Available GPUs:") if (grid.getNumGPUs() > 0): for iGPU in range(grid.getNumGPUs()): sName = "" if ("@CMAKE_CXX_COMPILER_ID@" == "MSVC"): sName = "Unavailable under Windows" else: sName = grid.getGPUName(iGPU) sMem = grid.getGPUMemory(iGPU) print(" {0:2d}: {1:20s} with{2:6d}MB RAM".format(iGPU, sName, sMem)) else: print(" none") # covers the printStats() in python and C++ grid.printStats() # empty grid grid.makeGlobalGrid(2, 0, 1, "level", "gauss-gegenbauer", [], 3.0) grid.printStats() grid.makeGlobalGrid(2, 0, 1, "level", "gauss-jacobi", [], 3.0, 3.0) grid.printStats() grid.makeGlobalGrid(2, 1, 1, "level", "custom-tabulated", [], 0.0, 0.0, tdata.sGaussPattersonTableFile) grid.printStats() grid.makeSequenceGrid(2, 1, 3, "level", "rleja") ttc.loadExpN2(grid) grid.printStats() grid.makeLocalPolynomialGrid(1, 1, 3) grid.setDomainTransform(np.array([[2.0, 3.0]])) grid.printStats() grid.makeWaveletGrid(2, 1, 1) grid.printStats() grid.makeFourierGrid(3, 1, 1, "level") grid.enableAcceleration("gpu-cuda") grid.printStats() def checkReadWriteGlobal(self): ''' Test reading and writing of Global grids. ''' # iDimension, iOutputs, iDepth, sType, sRule, fAlpha, fBeta, useTransform, loadFunciton, limitLevels lGrids = [[3, 2, 2, "level", "leja", 0.0, 0.0, False, False, False], [2, 1, 4, "level", "clenshaw-curtis", 0.0, 0.0, False, False, False], [3, 1, 3, "level", "rleja", 0.0, 0.0, True, False, False], [3, 1, 2, "iptotal", "chebyshev", 0.0, 0.0, False, True, False], [3, 1, 3, "level", "leja", 0.0, 0.0, True, True, False], [3, 1, 3, "level", "leja", 0.0, 0.0, True, True, True], [2, 1, 5, "qptotal", "gauss-hermite", 1.0, 3.0, False, False, False], [3, 1, 2, "level", "gauss-laguerre", 3.0, 0.0, False, False, True],] aTransform = np.array([[0.0,1.0],[0.0,1.0],[-2.0,-1.0]]) for lT in lGrids: gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() if (lT[7]): gridA.makeGlobalGrid(lT[0], lT[1], lT[2], lT[3], lT[4], [], lT[5], lT[6], [], [3, 2, 1]) else: gridA.makeGlobalGrid(lT[0], lT[1], lT[2], lT[3], lT[4], [], lT[5], lT[6]) #gridA.printStats() if (lT[7]): gridA.setDomainTransform(aTransform) if (lT[8]): ttc.loadExpN2(gridA) gridA.write("testSave", bUseBinaryFormat = False) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridA.write("testSave", bUseBinaryFormat = True) gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridB.makeGlobalGrid(1, 0, 1, "level", "rleja") gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.copyGrid(gridA) ttc.compareGrids(gridA, gridB) # test an error message from wrong read try: gridB.read("Test_If_Bogus_Filename_Produces_an_Error") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "sFilename", "Reading a bogus file properly failed, but the error information is wrong.") # custom rule test gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() gridA.makeGlobalGrid(2, 0, 4, 'level', 'custom-tabulated', [], 0.0, 0.0, tdata.sGaussPattersonTableFile) gridB = TasmanianSG.TasmanianSparseGrid() gridB.makeGlobalGrid(2, 0, 4, 'level', 'gauss-patterson') ttc.compareGrids(gridA, gridB, bTestRuleNames = False) gridA.write("testSave", bUseBinaryFormat = False) gridB.makeGlobalGrid(2, 0, 4, 'level', 'clenshaw-curtis') gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridA.write("testSave", bUseBinaryFormat = True) gridB.makeGlobalGrid(3, 0, 4, 'level', 'leja') gridB.read("testSave") ttc.compareGrids(gridA, gridB) def checkReadWriteSequence(self): ''' Test reading and writing of Sequence grids. ''' # iDimension, iOutputs, iDepth, sType, sRule, useTransform, loadFunciton, limitLevels lGrids = [[3, 2, 2, "level", "leja", False, False, False], [2, 1, 4, "level", "max-lebesgue", False, False, False], [3, 1, 3, "level", "rleja", True, False, False], [3, 1, 3, "level", "rleja", True, False, True], [3, 1, 2, "iptotal", "min-delta", False, True, False], [3, 1, 3, "level", "leja", True, True, False], [3, 1, 3, "level", "leja", True, True, True],] for lT in lGrids: gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() if (lT[7]): gridA.makeSequenceGrid(lT[0], lT[1], lT[2], lT[3], lT[4], [], [2, 3, 1]) else: gridA.makeSequenceGrid(lT[0], lT[1], lT[2], lT[3], lT[4]) if (lT[5]): gridA.setDomainTransform(np.array([[0.0,1.0],[0.0,1.0],[-2.0,-1.0]])) if (lT[6]): ttc.loadExpN2(gridA) gridA.write("testSave", bUseBinaryFormat = False) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridA.write("testSave", bUseBinaryFormat = True) gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridB.makeGlobalGrid(1, 0, 1, "level", "rleja") gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.copyGrid(gridA) ttc.compareGrids(gridA, gridB) def checkReadWriteLocalp(self): ''' Test reading and writing of Localp grids. ''' # iDimension, iOutputs, iDepth, iorder, sRule, useTransform, loadFunciton, limitLevels lGrids = [[3, 2, 2, 0, "localp", False, False, False], [3, 0, 2, 0, "localp-boundary", False, False, False], [2, 1, 4, 1, "semi-localp", False, False, False], [3, 1, 3, 2, "localp", True, False, False], [3, 1, 2, 3, "localp-zero", False, True, False], [3, 1, 2, 3, "localp-zero", False, True, True], [3, 1, 3, 4, "semi-localp", True, True, False], [3, 1, 3, -1, "semi-localp", True, True, False], [3, 1, 3, -1, "semi-localp", True, True, True],] for lT in lGrids: gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() if (lT[7]): gridA.makeLocalPolynomialGrid(lT[0], lT[1], lT[2], lT[3], lT[4], [3, 1, 2]) else: gridA.makeLocalPolynomialGrid(lT[0], lT[1], lT[2], lT[3], lT[4]) if (lT[5]): gridA.setDomainTransform(np.array([[0.0,1.0],[0.0,1.0],[-2.0,-1.0]])) if (lT[6]): ttc.loadExpN2(gridA) gridA.write("testSave", bUseBinaryFormat = False) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridA.write("testSave", bUseBinaryFormat = True) gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridB.makeGlobalGrid(1, 0, 1, "level", "rleja") gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.copyGrid(gridA) ttc.compareGrids(gridA, gridB) def checkReadWriteWavelet(self): ''' Test reading and writing of Wavelet grids. ''' # iDimension, iOutputs, iDepth, iOrder, useTransform, loadFunciton lGrids = [[3, 2, 2, 1, False, False, False], [3, 0, 2, 1, False, False, False], [2, 1, 4, 1, False, False, False], [3, 1, 1, 3, True, False, False], [3, 1, 1, 3, True, False, True], [3, 1, 2, 1, False, True, False], [3, 1, 2, 3, True, True, True], [3, 1, 2, 3, True, True, False],] for lT in lGrids: gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() if (lT[6]): gridA.makeWaveletGrid(lT[0], lT[1], lT[2], lT[3], [1, 1, 2]) else: gridA.makeWaveletGrid(lT[0], lT[1], lT[2], lT[3]) if (lT[4]): gridA.setDomainTransform(np.array([[0.0,1.0],[0.0,1.0],[-2.0,-1.0]])) if (lT[5]): ttc.loadExpN2(gridA) gridA.write("testSave", bUseBinaryFormat = False) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridA.write("testSave", bUseBinaryFormat = True) gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridB.makeGlobalGrid(1, 0, 1, "level", "rleja") gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.copyGrid(gridA) ttc.compareGrids(gridA, gridB) def checkReadWriteFourier(self): ''' Test reading and writing of Fourier grids. ''' # iDimension, iOutputs, iDepth, useTransform, loadFunction, useLevelLimits lGrids = [[3, 2, 2, False, False, False], [2, 1, 4, False, False, False], [3, 1, 1, True, False, False], [3, 1, 1, True, False, True], [3, 1, 2, False, True, False], [3, 1, 2, True, True, True], [3, 1, 2, True, True, False],] for lT in lGrids: gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() if (lT[5]): gridA.makeFourierGrid(lT[0], lT[1], lT[2], 'level', [1, 1, 2]) else: gridA.makeFourierGrid(lT[0], lT[1], lT[2], 'level') if (lT[3]): gridA.setDomainTransform(np.array([[0.0,1.0],[0.0,1.0],[-2.0,-1.0]])) if (lT[4]): ttc.loadExpN2(gridA) gridA.write("testSave", bUseBinaryFormat = False) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridA.write("testSave", bUseBinaryFormat = True) gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridB.makeGlobalGrid(1, 0, 1, "level", "rleja") gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.copyGrid(gridA) ttc.compareGrids(gridA, gridB) def checkCopySubgrid(self): grid = TasmanianSG.TasmanianSparseGrid() # test grid gridTotal = TasmanianSG.TasmanianSparseGrid() # test grid gridRef1 = TasmanianSG.TasmanianSparseGrid() # test grid gridRef2 = TasmanianSG.TasmanianSparseGrid() # test grid gridRef3 = TasmanianSG.TasmanianSparseGrid() # test grid gridRef4 = TasmanianSG.TasmanianSparseGrid() # test grid # outputs: source 0 0, 1, 2 2, 3, 4 5 lGrids = ['gridTotal', 'gridRef1', 'gridRef2', 'gridRef3', 'gridRef4'] lOutputs = [6, 1, 3, 3, 1]; lMake = ['.makeGlobalGrid(2, iOutputs, 4, "level", "clenshaw-curtis")', '.makeSequenceGrid(2, iOutputs, 4, "level", "rleja")', '.makeLocalPolynomialGrid(2, iOutputs, 4, 2)', '.makeWaveletGrid(2, iOutputs, 3)', '.makeFourierGrid(2, iOutputs, 4, "level")'] for sMake in lMake: for iI in range(len(lOutputs)): iOutputs = lOutputs[iI] exec(lGrids[iI] + sMake) gridTotalValues = [] gridRef1Values = [] gridRef2Values = [] gridRef3Values = [] gridRef4Values = [] aPoints = gridTotal.getPoints() for iI in range(aPoints.shape[0]): lModel = [i * np.exp(aPoints[iI][0] + aPoints[iI][1]) for i in range(1, 7)] gridTotalValues.append(lModel) gridRef1Values.append(lModel[0:1]) gridRef2Values.append(lModel[0:3]) gridRef3Values.append(lModel[2:5]) gridRef4Values.append(lModel[5:6]) for sGrid in lGrids: exec(sGrid + ".loadNeededPoints(np.row_stack(" + sGrid + "Values))") grid.copyGrid(gridTotal) ttc.compareGrids(grid, gridTotal) grid.copyGrid(gridTotal, 0, 1) ttc.compareGrids(grid, gridRef1) grid.copyGrid(gridTotal, 0, 3) ttc.compareGrids(grid, gridRef2) grid.copyGrid(gridTotal, 2, 5) ttc.compareGrids(grid, gridRef3) grid.copyGrid(gridTotal, 5, 6) ttc.compareGrids(grid, gridRef4) def checkReadWriteMisc(self): ''' Test reading and writing of domain transforms and testing all rules. ''' lGrids = ['gridA.makeGlobalGrid(3, 2, 4, "level", "clenshaw-curtis"); gridA.setDomainTransform(aTransform); gridA.setConformalTransformASIN(np.array([3,4,5]))', 'gridA.makeGlobalGrid(3, 2, 4, "level", "gauss-legendre"); gridA.setConformalTransformASIN(np.array([3,5,1]))', 'gridA.makeSequenceGrid(2, 2, 5, "level", "leja"); gridA.setConformalTransformASIN(np.array([0,4]))', 'gridA.makeLocalPolynomialGrid(3, 1, 4, 2, "localp"); gridA.setDomainTransform(aTransform); gridA.setConformalTransformASIN(np.array([5,3,0]))', 'gridA.getNumPoints()'] aTransform = np.array([[0.0,1.0],[0.0,1.0],[-2.0,-1.0]]) for sGrid in lGrids: gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() exec(sGrid) gridA.write("testSave", bUseBinaryFormat = False) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridA.write("testSave", bUseBinaryFormat = True) gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridB.makeSequenceGrid(1, 1, 0, "level", "leja"); gridB.makeLocalPolynomialGrid(1, 1, 0) gridB.copyGrid(gridA) ttc.compareGrids(gridA, gridB) # Make a grid with every possible rule (catches false-positive and memory crashes) for sType in TasmanianSG.lsTsgGlobalTypes: for sRule in TasmanianSG.lsTsgGlobalRules: if ("custom-tabulated" in sRule): gridA.makeGlobalGrid(2, 0, 2, sType, sRule, sCustomFilename = tdata.sGaussPattersonTableFile) else: gridA.makeGlobalGrid(2, 0, 2, sType, sRule) gridA.write("testSave", bUseBinaryFormat = False) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridB.makeGlobalGrid(1, 0, 0, "level", "clenshaw-curtis") gridA.write("testSave", bUseBinaryFormat = True) gridB.read("testSave") for sType in TasmanianSG.lsTsgGlobalTypes: for sRule in TasmanianSG.lsTsgSequenceRules: gridA.makeSequenceGrid(2, 1, 3, sType, sRule) gridA.write("testSave", bUseBinaryFormat = False) gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridB.makeGlobalGrid(1, 0, 0, "level", "clenshaw-curtis") gridA.write("testSave", bUseBinaryFormat = True) gridB.read("testSave") ttc.compareGrids(gridA, gridB) def checkReadWriteCustomTabulated(self): ''' Test reading and writing of the CustomTabulated class. ''' description = "testCT" def create_nodes(j): return np.linspace(-1.0, 1.0, num=j) def create_weights(j): weights = np.linspace(0.0, 1.0, num=j) weights = 2.0 * weights / weights.sum() return weights # Read and write from explicitly given data. for i in range(4): num_levels = i num_nodes = np.array([3*(j+1) for j in range(i)]) precision = np.array([2*(j+1)-1 for j in range(i)]) nodes = [create_nodes(j) for j in num_nodes] weights = [create_weights(j) for j in num_nodes] ctA = TasmanianSG.makeCustomTabulatedFromData(num_levels, num_nodes, precision, nodes, weights, description) # . ctB = TasmanianSG.CustomTabulated() ctA.write("testSave") ctB.read("testSave") for i in range(num_levels): read_weights, read_nodes = ctB.getWeightsNodes(i) np.testing.assert_almost_equal(read_weights, weights[i]) np.testing.assert_almost_equal(read_nodes, nodes[i]) # Read and write from a file. ctA = TasmanianSG.makeCustomTabulatedFromFile(tdata.sGaussPattersonTableFile) ctB = TasmanianSG.CustomTabulated() ctA.write("testSave") ctB.read("testSave") ttc.compareCustomTabulated(ctA, ctB) for i in range(ctB.getNumLevels()): read_weights, read_nodes = ctB.getWeightsNodes(i) grid = TasmanianSG.makeGlobalGrid(1, 0, i, "level", "gauss-patterson") np.testing.assert_almost_equal(read_weights, grid.getQuadratureWeights()) np.testing.assert_almost_equal(read_nodes, grid.getPoints().flatten()) # Test an error message from wrong read. try: ctB.read("Test_If_Bogus_Filename_Produces_an_Error") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "sFilename", "Reading a bogus file properly failed, but the error information is wrong.") def checkGlobalGridCustom(self): ''' Test makeGlobalGridCustom(), which creates a grid from a CustomTabulated instance. ''' gridA = TasmanianSG.makeGlobalGrid(1, 1, 3, "level", "custom-tabulated", [], 0.0, 0.0, tdata.sGaussPattersonTableFile) ct = TasmanianSG.makeCustomTabulatedFromFile(tdata.sGaussPattersonTableFile) gridB = TasmanianSG.makeGlobalGridCustom(1, 1, 3, "level", ct) ttc.compareGrids(gridA, gridB) gridA = TasmanianSG.makeGlobalGrid(2, 1, 3, "level", "custom-tabulated", [], 0.0, 0.0, tdata.sGaussPattersonTableFile) gridB = TasmanianSG.makeGlobalGridCustom(2, 1, 3, "level", ct) ttc.compareGrids(gridA, gridB) def performIOTest(self): self.checkMetaIO() self.checkReadWriteGlobal() self.checkReadWriteSequence() self.checkReadWriteLocalp() self.checkReadWriteWavelet() self.checkReadWriteFourier() self.checkCopySubgrid() self.checkReadWriteMisc() self.checkReadWriteCustomTabulated() self.checkGlobalGridCustom() TASMANIAN-8.1/InterfacePython/testCommon.py000066400000000000000000000220351470551176200205130ustar00rootroot00000000000000import unittest import TasmanianSG import sys, os import numpy as np class TestTasCommon(unittest.TestCase): ''' The class contains functions and untilities that will be used in many places throughout the testing suite. The class needs to run a "dummy" test from within the class constructor, otherwise an object cannot be initialized from outside of this module. ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def compareGrids(self, gridA, gridB, bTestRuleNames = True): ''' Compaes two grids by checking points, weights, and several evaluate. The evaluates are done on a canonical [-1, 1] interval. The test passes if the grids are mathematically idential. bTestRuleNames should be True in most cases, i.e., check if the names of the rule in each grid matches. The exception is when comparing the GaussPatterson grids build with custom file and sRule = "gauss-patterson" ''' # test basic number of points data self.assertEqual(gridA.getNumDimensions(), gridB.getNumDimensions(), "error in getNumDimensions()") self.assertEqual(gridA.getNumOutputs(), gridB.getNumOutputs(), "error in getNumOutputs()") self.assertEqual(gridA.getNumPoints(), gridB.getNumPoints(), "error in getNumPoints()") self.assertEqual(gridA.getNumLoaded(), gridB.getNumLoaded(), "error in getNumLoaded()") self.assertEqual(gridA.getNumNeeded(), gridB.getNumNeeded(), "error in getNumNeeded()") self.assertEqual(gridA.isUsingConstruction(), gridB.isUsingConstruction(), "error in isUsingConstruction()") if (gridA.getNumPoints() == 0): # emptry grid, nothing else to check return # load test points (canonical domain only), make sure to avoid grid points, e.g., 1/2, 1/4, etc. if (gridA.getNumDimensions() == 1): mX1 = np.array([1.0/3.0]) mX2 = np.array([-1.0/3.0]) mX3 = np.array([-1.0/5.0]) mX4 = np.array([1.0/7.0]) mX5 = np.array([-1.0/7.0]) elif (gridA.getNumDimensions() == 2): mX1 = np.array([1.0/3.0, 1.0/6.0]) mX2 = np.array([-1.0/3.0, 1.0/6.0]) mX3 = np.array([-1.0/5.0, -1.0/7.0]) mX4 = np.array([1.0/7.0, 1.0/5.0]) mX5 = np.array([-1.0/7.0, -1.0/13.0]) elif (gridA.getNumDimensions() == 3): mX1 = np.array([1.0/3.0, 1.0/6.0, -1.0/5.0]) mX2 = np.array([-1.0/3.0, 1.0/6.0, 1.0/6.0]) mX3 = np.array([-1.0/5.0, -1.0/7.0, 1.0/3.0]) mX4 = np.array([1.0/7.0, 1.0/5.0, 2.0/3.0]) mX5 = np.array([-1.0/7.0, -1.0/13.0, -2.0/3.0]) aBatchPoints = np.row_stack([mX1, mX2, mX3, mX4, mX5]) pA = gridA.getPoints() pB = gridB.getPoints() np.testing.assert_equal(pA, pB, "Points not equal", True) pA = gridA.getLoadedPoints() pB = gridB.getLoadedPoints() np.testing.assert_equal(pA, pB, "Loaded not equal", True) pA = gridA.getNeededPoints() pB = gridB.getNeededPoints() np.testing.assert_equal(pA, pB, "Needed not equal", True) # test rule data self.assertEqual(gridA.getAlpha(), gridB.getAlpha(), "error in getAlpha()") self.assertEqual(gridA.getBeta(), gridB.getBeta(), "error in getBeta()") self.assertEqual(gridA.getOrder(), gridB.getOrder(), "error in getOrder()") if (bTestRuleNames): self.assertEqual(gridA.getRule(), gridB.getRule(), "error in getRule()") self.assertEqual(gridA.getCustomRuleDescription(), gridB.getCustomRuleDescription(), "error in getCustomRuleDescription()") self.assertEqual(gridA.isGlobal(), gridB.isGlobal(), "error in isGlobal()") self.assertEqual(gridA.isSequence(), gridB.isSequence(), "error in isSequence()") self.assertEqual(gridA.isLocalPolynomial(), gridB.isLocalPolynomial(), "error in isLocalPolynomial()") self.assertEqual(gridA.isWavelet(), gridB.isWavelet(), "error in isWavelet()") self.assertEqual(gridA.isFourier(), gridB.isFourier(), "error in isFourier()") # weights pA = gridA.getQuadratureWeights() pB = gridB.getQuadratureWeights() np.testing.assert_almost_equal(pA, pB, 14, "Quadrature not equal", True) pA = gridA.getInterpolationWeights(mX1) pB = gridB.getInterpolationWeights(mX1) np.testing.assert_almost_equal(pA, pB, 14, "Interpolation test 1 not equal", True) pA = gridA.getInterpolationWeights(mX2) pB = gridB.getInterpolationWeights(mX2) np.testing.assert_almost_equal(pA, pB, 14, "Interpolation test 2 not equal", True) pA = gridA.getInterpolationWeights(mX3) pB = gridB.getInterpolationWeights(mX3) np.testing.assert_almost_equal(pA, pB, 14, "Interpolation test 3 not equal", True) # evaluate (values have been loaded) if (gridA.getNumLoaded() > 0): pA = gridA.evaluate(mX4) pB = gridB.evaluate(mX4) np.testing.assert_almost_equal(pA, pB, 12, "Interpolation test 4 not equal", True) pA = gridA.evaluate(mX5) pB = gridB.evaluate(mX5) np.testing.assert_almost_equal(pA, pB, 12, "Interpolation test 5 not equal", True) pA = gridA.integrate() pB = gridB.integrate() np.testing.assert_almost_equal(pA, pB, 12, "Integration test not equal", True) pA = gridA.evaluateBatch(aBatchPoints) pB = gridB.evaluateBatch(aBatchPoints) np.testing.assert_almost_equal(pA, pB, 12, "Interpolation test 6 (batch) not equal", True) pA = gridA.getHierarchicalCoefficients() pB = gridB.getHierarchicalCoefficients() np.testing.assert_almost_equal(pA, pB, 12, "getHierarchicalCoefficients() not equal", True) # domain transforms self.assertEqual(gridA.isSetDomainTransfrom(), gridB.isSetDomainTransfrom(), "error in isSetDomainTransfrom()") pA = gridA.getDomainTransform() pB = gridB.getDomainTransform() np.testing.assert_equal(pA, pB, "Domain test no equal", True) self.assertEqual(gridA.isSetConformalTransformASIN(), gridB.isSetConformalTransformASIN(), "error in isSetConformalTransformASIN()") pA = gridA.getLevelLimits() pB = gridB.getLevelLimits() np.testing.assert_equal(pA, pB, "Level limit test no equal", True) pA = gridA.getConformalTransformASIN() pB = gridB.getConformalTransformASIN() np.testing.assert_equal(pA, pB, "Conformal transform ASIN not equal", True) def compareCustomTabulated(self, ctA, ctB): ''' Compaes two CustomTabulated instances by checking nodes, weights, and other metadata. The test passes if the two instances are mathematically identical. ''' # Test metadata. self.assertEqual(ctA.getDescription(), ctB.getDescription(), "error in getDescription()") self.assertEqual(ctA.getNumLevels(), ctB.getNumLevels(), "error in getNumLevels()") for level in range(ctA.getNumLevels()): self.assertEqual(ctA.getNumPoints(level), ctB.getNumPoints(level), "error in getNumPoints() at level " + str(level)) self.assertEqual(ctA.getIExact(level), ctB.getIExact(level), "error in getIExact() at level " + str(level)) self.assertEqual(ctA.getQExact(level), ctB.getQExact(level), "error in getQExact() at level " + str(level)) wA, nA = ctA.getWeightsNodes(level) wB, nB = ctB.getWeightsNodes(level) np.testing.assert_equal(wA, wB, "Weights from getWeightsNodes() are not equal at level " + str(level), True) np.testing.assert_equal(nA, nB, "Nodes from getWeightsNodes() are not equal at level " + str(level), True) def loadExpN2(self, grid): ''' If there are needed points, load the points with exp(-sum(x)**2) where x is each of the needed points. The function is needed to test whether read/write correctly works on the loaded values, so some values have to be easily loaded even if they are not meaningful as in the convergence/correctness tests. ''' if (grid.getNumNeeded() == 0): return mPoints = grid.getNeededPoints() iOut = grid.getNumOutputs() iDim = grid.getNumDimensions() grid.loadNeededPoints(np.column_stack([np.exp(-np.sum(mPoints**2, axis=1)) for i in range(iOut)])) def checkPoints(self, aPoints, lMustHave, lMustNotHave): ''' aPoints is 1D array of points lMustHave and lMustNotHave are the points to test Example: checkPoints(aPoints[:,0], [0.0, 1.0, -1.0], [0.5, -0.5]) ''' for x in lMustHave: self.assertTrue((np.sum(np.where(np.abs(aPoints - x) < 0.001, 1, 0)) > 0), 'did not properly limit level, did not find {0:1.5e}'.format(x)) for x in lMustNotHave: self.assertTrue((np.sum(np.where(np.abs(aPoints - x) < 0.001, 1, 0)) == 0), 'did not properly limit level, did find {0:1.5e}'.format(x)) TASMANIAN-8.1/InterfacePython/testConfigureData.in.py000066400000000000000000000014411470551176200224010ustar00rootroot00000000000000######################################################################## # This file will be configured by CMake (or pre-configured for GNU Make) # The information here will be omnipresent throughout the testing # environment, which will reduce the need for configuring. ######################################################################## bEnableSyncTests = True sLibPath = "@Tasmanian_libsparsegrid_path@" iGPUID = @Tasmanian_TESTS_GPU_ID@ bHasBlas = ("@Tasmanian_ENABLE_BLAS@" == "ON") bHasSycl = ("@Tasmanian_ENABLE_DPCPP@" == "ON") bHasCuBlas = bHasSycl or ("@Tasmanian_ENABLE_CUDA@" == "ON") or ("@Tasmanian_ENABLE_HIP@" == "ON") bHasCuda = bHasCuBlas bUsingMSVC = ("@CMAKE_CXX_COMPILER_ID@" == "MSVC") sGaussPattersonTableFile = "@CMAKE_CURRENT_BINARY_DIR@/GaussPattersonRule.table" TASMANIAN-8.1/InterfacePython/testDream.py000066400000000000000000000122201470551176200203060ustar00rootroot00000000000000import unittest import Tasmanian DREAM = Tasmanian.DREAM import os import numpy as np import testCommon ttc = testCommon.TestTasCommon() class TestTasClass(unittest.TestCase): ''' Tests for the Tasmanian DREAM python bindings module ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def checkGaussian3D(self): iNumDimensions = 3 iNumSamples = 1000 iNumChains = 20 iNumIterations = int(iNumSamples / iNumChains) + 2 iNumBurnup = iNumIterations state = DREAM.State(iNumChains, iNumDimensions) state.setState(DREAM.genGaussianSamples([2.0, 2.0, 2.0], [3.0, 3.0, 3.0], iNumChains, DREAM.RandomGenerator("minstd_rand", 42))) DREAM.Sample(iNumBurnup, iNumSamples, lambda x : np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), # Gaussian mean 2.0 variance 9.0 DREAM.Domain("unbounded"), state, DREAM.IndependentUpdate("gaussian", 3.0), DREAM.DifferentialUpdate(0), DREAM.RandomGenerator("minstd_rand", 42)) aMean, aVar = state.getHistoryMeanVariance() self.assertTrue(np.max(np.abs(aMean - 2.0)) < 0.2, "Failed the mean test for Gaussian 3D") self.assertTrue(np.max(np.abs(aVar - 9.0)) < 1.0, "Failed the variance test for Gaussian 3D") state = DREAM.State(iNumChains, iNumDimensions) state.setState(DREAM.genGaussianSamples([1.5, 2.0, 2.5], [0.5, 1.0, 2.0], iNumChains, DREAM.RandomGenerator("minstd_rand", 42))) likely = DREAM.LikelihoodGaussAnisotropic(np.array([0.25, 1.0, 4.0]), np.array([1.5, 2.0, 2.5]), 1) DREAM.Sample(iNumBurnup, iNumSamples, lambda x : likely.getLikelihood(DREAM.typeLogform, x), # Gaussian mean 2.0 variance 9.0 DREAM.Domain("unbounded"), state, DREAM.IndependentUpdate("gaussian", 3.0), DREAM.DifferentialUpdate(97), DREAM.RandomGenerator("minstd_rand", 72), DREAM.typeLogform) aMean, aVar = state.getHistoryMeanVariance() self.assertTrue(np.max(np.abs(aMean - np.array([1.5, 2.0, 2.5]))) < 0.4, "Failed the mean test for anisotropic Gaussian 3D") self.assertTrue(np.max(np.abs(aVar - np.array([0.25, 1.0, 4.0]))) < 1.0, "Failed the variance test for anisotropic Gaussian 3D") def checkGrid(self): iNumDimensions = 2 iNumSamples = 1000 iNumChains = 20 iNumIterations = int(iNumSamples / iNumChains) + 2 iNumBurnup = iNumIterations grid = Tasmanian.SparseGrid() grid.makeSequenceGrid(2, 1, 24, "level", "rleja") Tasmanian.loadNeededPoints(lambda x, tid : np.ones((1,)) * np.exp( -0.5 * np.sum((x - 0.3)**2) / 0.01 ), grid, 1) state = DREAM.State(iNumChains, grid) state.setState(DREAM.genGaussianSamples([0.3, 0.3], [0.1, 0.1], iNumChains, DREAM.RandomGenerator("minstd_rand", 55))) DREAM.Sample(iNumBurnup, iNumSamples, DREAM.PosteriorEmbeddedLikelihood(grid, "uniform"), DREAM.Domain("hypercube", np.array((0.0, 0.0)), np.array((1.0, 1.0))), state, DREAM.IndependentUpdate("uniform", 0.1), DREAM.DifferentialUpdate(98), DREAM.RandomGenerator("minstd_rand", 33)) aMean, aVar = state.getHistoryMeanVariance() self.assertTrue(np.max(np.abs(aMean - np.array([0.3, 0.3]))) < 0.05, "Failed the mean test for grid likelihood") self.assertTrue(np.max(np.abs(aVar - np.array([0.01, 0.01]))) < 0.005, "Failed the variance test for grid likelihood") def checkModel(self): iNumDimensions = 2 iNumSamples = 1000 iNumChains = 20 iNumIterations = int(iNumSamples / iNumChains) + 2 iNumBurnup = iNumIterations likely = DREAM.LikelihoodGaussIsotropic(0.01, np.array([1.0, 2.0])) state = DREAM.State(iNumChains, iNumDimensions) state.setState(DREAM.genUniformSamples([-1.0, -1.0], [1.0, 1.0], iNumChains, DREAM.RandomGenerator("minstd_rand", 67))) DREAM.Sample(iNumBurnup, iNumSamples, DREAM.Posterior(lambda x : np.matmul(np.cos(x), np.array([[1.0, 0.0], [0.0, 2.0]])), likely, "uniform", DREAM.typeLogform), DREAM.Domain("hypercube", np.array((0.0, 0.0)), np.array((1.0, 1.0))), state, DREAM.IndependentUpdate("uniform", 0.1), DREAM.DifferentialUpdate(98), DREAM.RandomGenerator("minstd_rand", 88), DREAM.typeLogform) aMode = state.getApproximateMode() self.assertTrue(np.max(np.abs(aMode)) < 0.01, "Failed the mode test for custom model and Tasmanian likelihood") def performDreamTests(self): self.checkGaussian3D() # analytic model/likelihood self.checkGrid() self.checkModel() # custom model if __name__ == "__main__": tester = TestTasClass() tester.performDreamTests() TASMANIAN-8.1/InterfacePython/testExceptions.py000066400000000000000000001026641470551176200214130ustar00rootroot00000000000000import unittest import Tasmanian DREAM = Tasmanian.DREAM Opt = Tasmanian.Optimization import numpy as np import testCommon ttc = testCommon.TestTasCommon() # tests should pass when errors are raised, thus suppress the verbose error messages # to avoid confusing a verbose message with a real error (i.e., failed test) Tasmanian.useVerboseErrors(False) class TestTasClass(unittest.TestCase): ''' Test the python exceptions, create a bunch of incorrect faults and check whether the correct exception is raised. ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def getSparseGridTests(self): # The list llTest contains list-of-lists (could make into tuples) # Each sub-list (tuple) has two entries, one is the command that should raise the exception, # the second is the "sError" variable in the exception class. # notError tests here are needed to ensure that the multi-statement commands fail for the correct function. return [["grid.makeGlobalGrid(-1, 1, 4, 'level', 'clenshaw-curtis')", "iDimension"], ["grid.makeGlobalGrid(2, -1, 4, 'level', 'clenshaw-curtis')", "iOutputs"], ["grid.makeGlobalGrid(2, 1, -4, 'level', 'clenshaw-curtis')", "iDepth"], ["grid.makeGlobalGrid(2, 1, 4, 'wrong', 'clenshaw-curtis')", "sType"], ["grid.makeGlobalGrid(2, 1, 4, 'level', 'clenshaw-wrong')", "sRule"], ["grid.makeGlobalGrid(2, 1, 4, 'level', 'clenshaw-curtis', [1,2,3])", "liAnisotropicWeights"], ["grid.makeGlobalGrid(2, 1, 4, 'level', 'clenshaw-curtis', [1,2], liLevelLimits = [1, 2, 3])", "liLevelLimits"], ["grid.makeGlobalGrid(2, 1, 4, 'level', 'clenshaw-curtis', [1,2], liLevelLimits = [1, 2])", "notError"], ["grid.makeSequenceGrid(-1, 1, 4, 'level', 'leja')", "iDimension"], ["grid.makeSequenceGrid(2, -1, 4, 'level', 'leja')", "iOutputs"], ["grid.makeSequenceGrid(2, 1, -4, 'level', 'leja')", "iDepth"], ["grid.makeSequenceGrid(2, 1, 4, 'wrong', 'leja')", "sType"], ["grid.makeSequenceGrid(2, 1, 4, 'level', 'weja')", "sRule"], ["grid.makeSequenceGrid(2, 1, 4, 'level', 'leja', [1, 2, 3])", "liAnisotropicWeights"], ["grid.makeSequenceGrid(2, 1, 4, 'level', 'leja', [1, 2], [1, 2, 3])", "liLevelLimits"], ["grid.makeSequenceGrid(2, 1, 4, 'level', 'leja', liLevelLimits = [1, 2])", "notError"], ["grid.makeLocalPolynomialGrid(-1, 1, 4, 2, 'localp')", "iDimension"], ["grid.makeLocalPolynomialGrid(2, -1, 4, 2, 'localp')", "iOutputs"], ["grid.makeLocalPolynomialGrid(2, 1, -4, 2, 'localp')", "iDepth"], ["grid.makeLocalPolynomialGrid(2, 1, 4, -2, 'localp')", "iOrder"], ["grid.makeLocalPolynomialGrid(2, 1, 4, 2, 'lowrong')", "sRule"], ["grid.makeLocalPolynomialGrid(2, 1, 4, 2, 'localp', [1, 2, 3])", "liLevelLimits"], ["grid.makeLocalPolynomialGrid(2, 1, 4, 2, 'localp', [1, 2])", "notError"], ["grid.makeWaveletGrid(-1, 1, 4, 1)", "iDimension"], ["grid.makeWaveletGrid(2, -1, 4, 1)", "iOutputs"], ["grid.makeWaveletGrid(2, 1, -4, 3)", "iDepth"], ["grid.makeWaveletGrid(2, 1, 4, 2)", "iOrder"], ["grid.makeWaveletGrid(2, 1, 4, 1, [1, 2, 3])", "liLevelLimits"], ["grid.makeWaveletGrid(2, 1, 4, 1, [2, 1])", "notError"], ["grid.makeFourierGrid(-1, 1, 4, 'level')", "iDimension"], ["grid.makeFourierGrid(2, -1, 4, 'level')", "iOutputs"], ["grid.makeFourierGrid(2, 1, -4, 'level')", "iDepth"], ["grid.makeFourierGrid(2, 1, 4, 'wrong')", "sType"], ["grid.makeFourierGrid(2, 1, 4, 'level', [1, 2, 3])", "liAnisotropicWeights"], ["grid.makeFourierGrid(2, 1, 4, 'level', [1, 2], [1, 2, 3])", "liLevelLimits"], ["grid.makeFourierGrid(2, 1, 4, 'level', liLevelLimits = [1, 2])", "notError"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja')", "notError"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'chebyshev')", "notError"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededValues(np.zeros([6,2]))", "notError"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); grid.updateGlobalGrid(1,'iptotal')", "updateGlobalGrid"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'chebyshev'); grid.updateGlobalGrid(-1,'iptotal')", "iDepth"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'chebyshev'); grid.updateGlobalGrid(4,'wrong')", "sType"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'chebyshev'); grid.updateGlobalGrid(4,'iptotal',[1,2,3])", "liAnisotropicWeights"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'chebyshev'); grid.updateGlobalGrid(4,'iptotal',liLevelLimits = [1,2,3])", "liLevelLimits"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'chebyshev'); grid.updateGlobalGrid(4,'iptotal',liLevelLimits = [1,2])", "notError"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'rleja'); grid.updateSequenceGrid(4,'iptotal')", "updateSequenceGrid"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); grid.updateSequenceGrid(-1,'iptotal')", "iDepth"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); grid.updateSequenceGrid(4,'wrong')", "sType"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); grid.updateSequenceGrid(4,'iptotal',[1,2,3])", "liAnisotropicWeights"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); grid.updateSequenceGrid(4,'iptotal',liLevelLimits = [1,2,3])", "liLevelLimits"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); grid.updateSequenceGrid(4,'iptotal',liLevelLimits = [2,3])", "notError"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); grid.updateFourierGrid(3,'level')", "updateFourierGrid"], ["grid.makeFourierGrid(2, 1, 2, 'level'); grid.updateFourierGrid(-3,'level')", "iDepth"], ["grid.makeFourierGrid(2, 1, 2, 'level'); grid.updateFourierGrid(3,'wrong')", "sType"], ["grid.makeFourierGrid(2, 1, 2, 'level'); grid.updateFourierGrid(3,'iptotal',[1])", "liAnisotropicWeights"], ["grid.makeFourierGrid(2, 1, 2, 'level'); grid.updateFourierGrid(3,'iptotal',liLevelLimits = [4])", "liLevelLimits"], ["grid.makeFourierGrid(2, 1, 2, 'level'); grid.updateFourierGrid(3,'iptotal', [4, 3], [4, 3])", "notError"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); aW = grid.getInterpolationWeights(np.array([1,2,3]))", "lfX"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); aW = grid.getInterpolationWeightsBatch(np.array([1,2,3]))", "llfX"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); aW = grid.getInterpolationWeightsBatch(np.array([[1,2,3],[1,2,3]]))", "llfX"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([1,]))", "llfVals"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([6,3]))", "llfVals"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([5,2]))", "llfVals"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([6,2])); grid.loadNeededPoints(np.ones([5,2]))", "llfVals"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.evaluate(np.zeros([1,2]))", "evaluate"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.evaluateThreadSafe(np.zeros(np.array([1,2])))", "evaluateThreadSafe"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([6,2])); grid.evaluate(np.zeros([1,3]))", "lfX"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([6,2])); grid.evaluate(np.zeros([3]))", "lfX"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([6,2])); grid.evaluateThreadSafe(np.zeros([1,3]))", "lfX"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([6,2])); grid.evaluateThreadSafe(np.zeros([3]))", "lfX"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.evaluateBatch(np.zeros([1,2]))", "evaluateBatch"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([6,2])); grid.evaluateBatch(np.zeros([1,3]))", "llfX"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.loadNeededPoints(np.zeros([6,2])); grid.evaluateBatch(np.zeros([2,]))", "llfX"], ["grid.makeSequenceGrid(2, 2, 2, 'level', 'rleja'); grid.integrate()", "integrate"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'gauss-legendre'); grid.setDomainTransform(np.zeros([2,]))", "llfTransform"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'gauss-legendre'); grid.setDomainTransform(np.zeros([2,1]))", "llfTransform"], ["grid.makeGlobalGrid(3, 1, 2, 'level', 'gauss-legendre'); grid.setDomainTransform(np.zeros([2,2]))", "llfTransform"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'gauss-legendre')", "notError"], ["grid.makeGlobalGrid(3, 1, 2, 'level', 'gauss-legendre'); grid.setDomainTransform(np.zeros([3,2]))", "notError"], ["grid.makeGlobalGrid(3, 1, 2, 'level', 'clenshaw-curtis');", "notError"], ["grid.makeGlobalGrid(3, 1, 2, 'level', 'clenshaw-curtis'); grid.setConformalTransformASIN(np.array([0,2,4]))", "notError"], ["grid.makeGlobalGrid(3, 1, 2, 'level', 'clenshaw-curtis'); grid.setConformalTransformASIN(np.array([0,2]))", "liTruncation"], ["grid.makeGlobalGrid(3, 1, 2, 'level', 'clenshaw-curtis'); grid.setConformalTransformASIN(np.array([[0,2,3],[1,2,3]]))", "liTruncation"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'rleja'); grid.setAnisotropicRefinement('iptotal', 10, 1);", "setAnisotropicRefinement"], ["grid.makeGlobalGrid(2, 0, 2, 'level', 'clenshaw-curtis'); grid.setAnisotropicRefinement('iptotal', 10, 1);", "setAnisotropicRefinement"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'fejer2'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', -2, 1);", "iMinGrowth"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', 10, -1);", "iOutput"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', 10, 0);", "notError"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', 10, 0, [2, 3]);", "notError"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', 10, 0, [2, 3, 3]);", "liLevelLimits"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', 10, -1);", "notError"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', 10, -2);", "iOutput"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', 10, 5);", "iOutput"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('wrong', 10, 0);", "sType"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', 10, -1, [3, 4]);", "notError"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.setAnisotropicRefinement('iptotal', 10, -1, [3, 4, 5]);", "liLevelLimits"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'rleja'); grid.estimateAnisotropicCoefficients('iptotal', 1);", "estimateAnisotropicCoefficients"], ["grid.makeGlobalGrid(2, 0, 2, 'level', 'clenshaw-curtis'); grid.estimateAnisotropicCoefficients('iptotal', 1);", "estimateAnisotropicCoefficients"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis'); ttc.loadExpN2(grid); grid.estimateAnisotropicCoefficients('iptotal', -1);", "iOutput"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.estimateAnisotropicCoefficients('iptotal', -1);", "notError"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.estimateAnisotropicCoefficients('ipcurved', -1);", "notError"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.estimateAnisotropicCoefficients('iptotal', -2);", "iOutput"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.estimateAnisotropicCoefficients('iptotal', 5);", "iOutput"], ["grid.makeSequenceGrid(2, 1, 3, 'iptotal', 'leja'); ttc.loadExpN2(grid); grid.estimateAnisotropicCoefficients('wrong', 0);", "sType"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis'); grid.setSurplusRefinement(1.E-4, 0, 'classic');", "setSurplusRefinement"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); grid.setSurplusRefinement(1.E-4, 0, 'classic');", "setSurplusRefinement"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); ttc.loadExpN2(grid); grid.setSurplusRefinement(-1.E-4, 0, 'classic');", "fTolerance"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, 'classic');", "sCriteria"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0);", "notError"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, '', [2, 3, 4]);", "liLevelLimits"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, '', [2, 3]);", "notError"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0);", "sCriteria"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, 'class');", "sCriteria"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, 'classic');", "notError"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, 'classic', [2, 3, 4]);", "liLevelLimits"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, 'classic', [], np.ones([3]));", "llfScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, 'classic', [], np.ones([grid.getNumPoints() - 1, 1]));", "llfScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, 'classic', [], np.ones([grid.getNumPoints(), 2]));", "llfScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 2, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, -1, 'classic', [], np.ones([grid.getNumPoints(), 2]));", "notError"], ["grid.makeLocalPolynomialGrid(2, 2, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, -1, 'classic', [], np.ones([grid.getNumPoints(), 3]));", "llfScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.setSurplusRefinement(1.E-4, 0, 'classic', [2, 3]);", "notError"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); grid.removePointsByHierarchicalCoefficient(1.E-4, 0);", "removePointsByHierarchicalCoefficient"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); grid.removePointsByHierarchicalCoefficient(-1.E-4, 0);", "fTolerance"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); grid.removePointsByHierarchicalCoefficient(1.E-4, -2);", "iOutput"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); grid.removePointsByHierarchicalCoefficient(1.E-4, 3);", "iOutput"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); grid.removePointsByHierarchicalCoefficient(1.E-4, 0);", "removePointsByHierarchicalCoefficient"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); ttc.loadExpN2(grid); grid.removePointsByHierarchicalCoefficient(1.E-4, 0);", "notError"], ["grid.makeLocalPolynomialGrid(2, 3, 2, 1, 'localp'); grid.loadNeededPoints(np.ones([grid.getNumNeeded(), grid.getNumOutputs()])); grid.removePointsByHierarchicalCoefficient(1.E-4, -1, np.ones([3,]));", "aScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 3, 2, 1, 'localp'); grid.loadNeededPoints(np.ones([grid.getNumNeeded(), grid.getNumOutputs()])); grid.removePointsByHierarchicalCoefficient(1.E-4, -1, np.ones([10,]));", "aScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 3, 2, 1, 'localp'); grid.loadNeededPoints(np.ones([grid.getNumNeeded(), grid.getNumOutputs()])); grid.removePointsByHierarchicalCoefficient(1.E-4, -1, np.ones([11,2]));", "aScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 3, 2, 1, 'localp'); grid.loadNeededPoints(np.ones([grid.getNumNeeded(), grid.getNumOutputs()])); grid.removePointsByHierarchicalCoefficient(1.E-4, -1, np.ones([13,2]));", "aScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 3, 2, 1, 'localp'); grid.loadNeededPoints(np.ones([grid.getNumNeeded(), grid.getNumOutputs()])); grid.removePointsByHierarchicalCoefficient(1.E-4, -1, np.ones([13,3]));", "notError"], ["grid.makeLocalPolynomialGrid(2, 3, 2, 1, 'localp'); grid.loadNeededPoints(np.ones([grid.getNumNeeded(), grid.getNumOutputs()])); grid.removePointsByHierarchicalCoefficient(1.E-4, 0, np.ones([13,3]));", "aScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 3, 2, 1, 'localp'); grid.loadNeededPoints(np.ones([grid.getNumNeeded(), grid.getNumOutputs()])); grid.removePointsByHierarchicalCoefficient(1.E-4, 0, np.ones([11,]));", "aScaleCorrection"], ["grid.makeLocalPolynomialGrid(2, 3, 2, 1, 'localp'); grid.loadNeededPoints(np.ones([grid.getNumNeeded(), grid.getNumOutputs()])); grid.removePointsByHierarchicalCoefficient(1.E-4, 0, np.ones([13,1]));", "notError"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis'); grid.evaluateHierarchicalFunctions(np.array([[1.0, 1.0], [0.5, 0.3]]));", "notError"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis'); grid.evaluateHierarchicalFunctions(np.array([[1.0,], [0.5,]]));", "llfX"], ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis'); grid.evaluateHierarchicalFunctions(np.array([1.0, 1.0]));", "llfX"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); grid.evaluateSparseHierarchicalFunctions(np.array([[1.0, 1.0], [0.5, 0.3]]));", "notError"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); grid.evaluateSparseHierarchicalFunctions(np.array([[1.0,], [0.5,]]));", "llfX"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); grid.evaluateSparseHierarchicalFunctions(np.array([1.0, 1.0]));", "llfX"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); grid.setHierarchicalCoefficients(np.array([1.0, 1.0]));", "llfCoefficients"], ["grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'localp'); grid.setHierarchicalCoefficients(np.array([[1.0, 1.0],]));", "llfCoefficients"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.setHierarchicalCoefficients(np.array([[1.0, 1.0],[1.0, 1.0],[1.0, 1.0],[1.0, 1.0],[1.0, 1.0],]));", "llfCoefficients"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.setHierarchicalCoefficients(np.array([[1.0,],[1.0,],[1.0,],[1.0,],[1.0,]]));", "notError"], ["grid.makeFourierGrid(2, 1, 1, 'level'); grid.setHierarchicalCoefficients(np.array([[1.0,],[1.0,],[1.0,],[1.0,],[1.0,]]));", "llfCoefficients"], ["grid.makeGlobalGrid(2, 1, 3, 'level', 'rleja'); grid.getCandidateConstructionPoints('level', -1);", "getCandidateConstructionPoints"], ["grid.makeGlobalGrid(2, 1, 3, 'level', 'rleja'); grid.beginConstruction(); grid.getCandidateConstructionPoints('lev', -1);", "sType"], ["grid.makeGlobalGrid(2, 1, 3, 'level', 'rleja'); grid.beginConstruction(); grid.getCandidateConstructionPoints('level', [0]);", "liAnisotropicWeightsOrOutput"], ["grid.makeGlobalGrid(2, 1, 3, 'level', 'rleja'); grid.beginConstruction(); grid.getCandidateConstructionPoints('level', 'string');", "liAnisotropicWeightsOrOutput"], ["grid.makeGlobalGrid(2, 1, 3, 'level', 'rleja'); grid.beginConstruction(); grid.getCandidateConstructionPoints('level', -1, [2]);", "liLevelLimits"], ["grid.makeGlobalGrid(2, 1, 3, 'level', 'rleja'); grid.beginConstruction(); grid.getCandidateConstructionPoints('level', -1, [2, 1]);", "notError"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.getCandidateConstructionPointsSurplus(1.E-5, 'classic');", "getCandidateConstructionPointsSurplus"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.getCandidateConstructionPointsSurplus(1.E-5, 'classic', 0, [2]);", "liLevelLimits"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.getCandidateConstructionPointsSurplus(1.E-5, 'classic', -1, [2, 3]);", "notError"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.loadConstructedPoint([0.0, 0.0], [1.0]);", "notError"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.loadConstructedPoint([0.0, 0.0], [1.0]);", "loadConstructedPoint"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.loadConstructedPoint([0.0], [1.0]);", "lfX"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.loadConstructedPoint([0.0, 0.0], [1.0, 2.0]);", "lfY"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.loadConstructedPoint([[0.0, 0.0], [1.0, 0.0]], [1.0, 2.0]);", "lfY"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.loadConstructedPoint([[0.0,], [1.0,]], [[1.0,], [2.0,]]);", "lfX"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.loadConstructedPoint([[0.0, 0.0], [1.0, 0.0]], [[1.0, 2.0], [1.0, 2.0]]);", "lfY"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.loadConstructedPoint([[0.0, 0.0], [1.0, 0.0]], [[1.0,], [2.0,], [3.0,]]);", "lfY"], ["grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp'); grid.beginConstruction(); grid.loadConstructedPoint([[[0.0, 0.0], [1.0, 0.0]],], [[1.0,], [2.0,]]);", "lfX"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); grid.enableAcceleration('gpu-wrong');", "sAccelerationType"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); grid.enableAcceleration('gpu-default');", "notError"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); grid.enableAcceleration('gpu-default', 0 if grid.isAccelerationAvailable('gpu-cuda') else None);", "notError"], ["grid.makeSequenceGrid(2, 1, 2, 'level', 'leja'); grid.enableAcceleration('gpu-default', -11);", "iGPUID"], ["grid1 = Tasmanian.SparseGrid(); grid1.isAccelerationAvailable('cpu-wrong');", "sAccelerationType"], ["grid1 = Tasmanian.SparseGrid(); grid1.isAccelerationAvailable('cpu-blas');", "notError"], ["grid1 = Tasmanian.SparseGrid(); grid1.getGPUMemory(-1);", "iGPUID"], ["grid1 = Tasmanian.SparseGrid(); grid1.getGPUMemory(1000000);", "iGPUID"], ["grid1 = Tasmanian.SparseGrid(); grid1.getGPUMemory(grid1.getNumGPUs());", "iGPUID"], ["grid1 = Tasmanian.SparseGrid(); grid1.getGPUName(-1);", "iGPUID"], ["grid1 = Tasmanian.SparseGrid(); grid1.getGPUName(1000000);", "iGPUID"], ["grid1 = Tasmanian.SparseGrid(); grid1.getGPUName(grid1.getNumGPUs());", "iGPUID"], ["grid1 = Tasmanian.SparseGrid(); grid1.setGPUID(-1);", "iGPUID"], ["grid1 = Tasmanian.SparseGrid(); grid1.setGPUID(1000000);", "iGPUID"], ["grid1 = Tasmanian.SparseGrid(); grid1.setGPUID(grid1.getNumGPUs());", "iGPUID"], ["grid.makeLocalPolynomialGrid(1, 1, 1, 1, 'localp'); Tasmanian.loadNeededPoints(lambda x, tid : x, grid, 1);", "notError"], ["grid.makeLocalPolynomialGrid(1, 1, 1, 1, 'localp'); Tasmanian.loadNeededPoints(lambda x, tid : np.ones((2,)) * x, grid, 1);", "loadNeededValues"], ] def getCustomTabulatedTests(self): # same format as in getSparseGridTests(). return [["Tasmanian.makeCustomTabulatedFromData(1, np.array([2]), np.array([1]), np.array([[0.0]]), np.array([[2.0]]), 'testCT')", "nodes[0]"], ["Tasmanian.makeCustomTabulatedFromData(1, np.array([2]), np.array([1]), np.array([[0.0, 1.0]]), np.array([[2.0]]), 'testCT')", "weights[0]"], ["Tasmanian.makeCustomTabulatedFromData(1, np.array([2, 3]), np.array([1]), np.array([[0.0, 1.0]]), np.array([[1.0, 1.0]]), 'testCT')", "num_nodes"], ["Tasmanian.makeCustomTabulatedFromData(1, np.array([2]), np.array([1, 2]), np.array([[0.0, 1.0]]), np.array([[1.0, 1.0]]), 'testCT')", "precision"], ] def getDreamTests(self): # see getSparseGridTests() for comments about the format return [["DREAM.Domain('incorrect')", "Domain"], ["DREAM.IndependentUpdate(1)", "sType"], ["DREAM.DifferentialUpdate(0.0)", "callableOrMagnitude"], ["DREAM.RandomGenerator('incorrect')", "sType"], ["DREAM.RandomGenerator(callableRNG = 0.0)", "callableRNG"], ["DREAM.Posterior(lambda x: x, lambda y: y, lambda x: 1, typeForm = 'incorrect')", "typeForm"], ["DREAM.Posterior('incorrect', lambda y: y, lambda x: 1)", "model"], ["DREAM.Posterior(lambda x: x, 'incorrect', lambda x: 1)", "likelihood"], ["DREAM.Posterior(lambda x: x, lambda y: y, 'prior')", "prior"], ["DREAM.genUniformSamples([0, 0], [1], 20)", "lfUpper"], ["DREAM.genGaussianSamples([0, 0], [1], 20)", "lfDeviation"], ["DREAM.State(3, 2).setState(np.array([[0.1, 0.1],[0.1, 0.2],[0.1, 0.3],]))", "notError"], ["DREAM.State(3, 2).setState(np.array([[0.1, 0.1],[0.1, 0.2],]))", "llfNewState"], ["DREAM.State(3, 2).setState(np.array([[0.1,],[0.1,],[0.1,],]))", "llfNewState"], ["""DREAM.Sample(5, 5, lambda x : np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), DREAM.Domain('unbounded'), state, DREAM.IndependentUpdate('gaussian', 3.0), DREAM.DifferentialUpdate(0))""", "notError"], ["""DREAM.Sample(5, 5, lambda x : np.ones((2, 1)) * np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), DREAM.Domain('unbounded'), state, DREAM.IndependentUpdate('gaussian', 3.0), DREAM.DifferentialUpdate(0))""", "Sample"], ["""DREAM.Sample(5, 5, lambda x : np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), DREAM.Domain('unbounded'), state, DREAM.IndependentUpdate(lambda : np.ones((3, 1))), DREAM.DifferentialUpdate(0))""", "Sample"], ["""DREAM.Sample(5, 5, DREAM.Domain('unbounded'), DREAM.Domain('unbounded'), state, DREAM.IndependentUpdate('gaussian', 3.0), DREAM.DifferentialUpdate(0))""", "probability_distibution"], ["""DREAM.Sample(5, 5, lambda x : np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), (-1.0, 1.0), state, DREAM.IndependentUpdate('gaussian', 3.0), DREAM.DifferentialUpdate(0))""", "domain_description"], ["""DREAM.Sample(5, 5, lambda x : np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), DREAM.Domain('unbounded'), grid, DREAM.IndependentUpdate('gaussian', 3.0), DREAM.DifferentialUpdate(0))""", "dream_state"], ["""DREAM.Sample(5, 5, lambda x : np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), DREAM.Domain('unbounded'), state, DREAM.DifferentialUpdate(0), DREAM.DifferentialUpdate(0))""", "independent_update"], ["""DREAM.Sample(5, 5, lambda x : np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), DREAM.Domain('unbounded'), state, DREAM.IndependentUpdate('gaussian', 3.0), DREAM.IndependentUpdate('gaussian', 3.0))""", "differential_update"], ["""DREAM.Sample(5, 5, lambda x : np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), DREAM.Domain('unbounded'), state, DREAM.IndependentUpdate('gaussian', 3.0), DREAM.DifferentialUpdate(0), lambda : 0.5)""", "random01"], ["""DREAM.Sample(5, 5, lambda x : np.exp( -0.5 * np.sum( (x - 2.0)**2, 1 ) / 9.0 ), DREAM.Domain('unbounded'), state, DREAM.IndependentUpdate('gaussian', 3.0), DREAM.DifferentialUpdate(0), typeForm = 'alpha')""", "typeForm"], ] def getOptimizationTests(self): # see getSparseGridTests() for comments about the format return [["pss.setParticlePositions(np.array([[1, 2, 3]]))", "llfNewPPosns"], ["pss.setParticlePositions(np.array([[1, 2], [2, 1]]))", "llfNewPPosns"], ["pss.setParticleVelocities(np.array([[1, 2, 3]]))", "llfNewPVelcs"], ["pss.setParticleVelocities(np.array([[1, 2], [2, 1]]))", "llfNewPVelcs"], ["pss.setBestParticlePositions(np.array([[1, 2, 3]]))", "llfNewBPPosns"], ["pss.initializeParticlesInsideBox(np.array([-1.0, -2.0, -3.0]), np.array([2.0, 1.0]))", "lfBoxLower"], ["pss.initializeParticlesInsideBox(np.array([-1.0, -2.0]), np.array([2.0, 1.0, 3.0]))", "lfBoxUpper"], ["pss.initializeParticlesInsideBox(np.array([-1.0, -2.0]), np.array([1.0, 3.0]));" + "f = lambda x_batch : np.append(np.apply_along_axis(np.sum, 1, x_batch), np.array([0.5]), axis=0);" + "inside = lambda x : True;" + "Opt.ParticleSwarm(f, inside, 0.5, 2, 2, 1, pss)", "ParticleSwarm"], ["pss.initializeParticlesInsideBox(np.array([-1.0, -2.0]), np.array([1.0, 3.0]));" + "f = lambda x_batch : np.apply_along_axis(np.sum, 1, x_batch);" + "inside = lambda x : 0.01;" + "Opt.ParticleSwarm(f, inside, 0.5, 2, 2, 1, pss)", "ParticleSwarm"], ] def testListedExceptions(self, llTests): grid = Tasmanian.SparseGrid() state = DREAM.State(10, 2) state.setState(DREAM.genGaussianSamples([-1.0, -1.0], [1.0, 1.0], 10, DREAM.RandomGenerator("minstd_rand", 42))) pss = Opt.ParticleSwarmState(2, 3) for lTest in llTests: try: exec(lTest[0]) self.assertEqual(lTest[1], "notError", "failed to raise exception for invalid '{0:1s}' using test\n '{1:1s}'".format(lTest[1],lTest[0])) except Tasmanian.TasmanianInputError as TSGError: self.assertEqual(TSGError.sVariable, lTest[1], "error raising exception for '{0:1s}' using test\n '{1:1s}'\n Error.sVariable = '{2:1s}'".format(lTest[1],lTest[0],TSGError.sVariable)) def performExceptionsTest(self): self.testListedExceptions(self.getSparseGridTests()) self.testListedExceptions(self.getCustomTabulatedTests()) self.testListedExceptions(self.getDreamTests()) self.testListedExceptions(self.getOptimizationTests()) TASMANIAN-8.1/InterfacePython/testMakeUpdate.py000066400000000000000000000502571470551176200213120ustar00rootroot00000000000000import unittest import Tasmanian import TasmanianSG # needed to test all rules import numpy as np import os, sys from ctypes import cdll from random import shuffle import testConfigureData as tdata # needed to keep track of version tests and ways to load the library import testCommon ttc = testCommon.TestTasCommon() class TestTasClass(unittest.TestCase): ''' Test make/update, check points, check library paths ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def checkPathsVersions(self): ''' Check different ways to specify the library path and check the version number. ''' grid = Tasmanian.TasmanianSparseGrid() sVersion = "{0:1d}.{1:1d}".format(grid.getVersionMajor(), grid.getVersionMinor()) self.assertEqual(sVersion, Tasmanian.__version__, "version mismatch") sLicense = grid.getLicense() self.assertEqual(sLicense, Tasmanian.__license__, "license mismatch") iVM = int(sVersion.split('.')[0]) iVm = int(sVersion.split('.')[1]) self.assertEqual(iVM, grid.getVersionMajor(), "version major mismatch") self.assertEqual(iVm, grid.getVersionMinor(), "version minor mismatch") def checkMakeAgainstKnown(self): ''' Make grids and check against pen-and-paper answers, check weights too. ''' grid = Tasmanian.makeGlobalGrid(1, 0, 4, 'level', 'gauss-hermite', [], 2.0) aW = grid.getQuadratureWeights() self.assertTrue(np.abs(sum(aW) - 0.5 * np.sqrt(np.pi)) < 1.E-14, "Gauss-Hermite Alpha") grid.makeGlobalGrid(2, 0, 2, 'level', 'leja', [2, 1]) aA = np.array([[0.0, 0.0], [0.0, 1.0], [0.0, -1.0], [1.0, 0.0]]) aP = grid.getPoints() np.testing.assert_equal(aA, aP, 'Anisotropy Global not equal', True) grid.makeGlobalGrid(2, 0, 4, 'ipcurved', 'leja', [20, 10, 0, 7]) aA = np.array([[0.0, 0.0], [0.0, 1.0], [0.0, -1.0], [0.0, np.sqrt(1.0/3.0)], [1.0, 0.0], [1.0, 1.0], [-1.0, 0.0]]) aP = grid.getPoints() np.testing.assert_almost_equal(aA, aP, 12, 'Anisotropy Global not equal', True) grid.makeSequenceGrid(2, 1, 2, 'level', 'leja', [2, 1]) aA = np.array([[0.0, 0.0], [0.0, 1.0], [0.0, -1.0], [1.0, 0.0]]) aP = grid.getPoints() np.testing.assert_equal(aA, aP, 'Anisotropy Sequence not equal', True) grid = Tasmanian.makeSequenceGrid(2, 1, 4, 'ipcurved', 'leja', [20, 10, 0, 7]) aA = np.array([[0.0, 0.0], [0.0, 1.0], [0.0, -1.0], [0.0, np.sqrt(1.0/3.0)], [1.0, 0.0], [1.0, 1.0], [-1.0, 0.0]]) aP = grid.getPoints() np.testing.assert_almost_equal(aA, aP, 12, 'Anisotropy Sequence not equal', True) grid = Tasmanian.makeFourierGrid(2, 1, 2, 'level', [1, 2]) aA = np.array([[0.0, 0.0], [0.0, 1.0/3.0], [0.0, 2.0/3.0], [1.0/3.0, 0.0], [2.0/3.0, 0.0], [1.0/9.0, 0.0], [2.0/9.0, 0.0], [4.0/9.0, 0.0], [5.0/9.0, 0.0], [7.0/9.0, 0.0], [8.0/9.0, 0.0]]) aP = grid.getPoints() np.testing.assert_almost_equal(aA, aP, 12, 'Anisotropy Fourier not equal', True) # this is a very important test, checks the curved rule and covers the non-lower-set index selection code grid.makeGlobalGrid(2, 1, 1, 'ipcurved', 'rleja', [10, 10, -21, -21]) aA = np.array([[0.0, 0.0], [0.0, 1.0], [0.0, 0.5], [0.0, 0.25], [0.0, 0.75], [0.0, 0.125], [1.0, 0.0], [1.0, 1.0], [1.0, 0.5], [1.0, 0.25], [1.0, 0.75], [1.0, 0.125], [0.5, 0.0], [0.5, 1.0], [0.5, 0.5], [0.5, 0.25], [0.5, 0.75], [0.5, 0.125], [0.25, 0.0], [0.25, 1.0], [0.25, 0.5], [0.25, 0.25], [0.25, 0.75], [0.75, 0.0], [0.75, 1.0], [0.75, 0.5], [0.75, 0.25], [0.125, 0.0], [0.125, 1.0], [0.125, 0.5]]) aA = np.cos(np.pi * aA) aP = grid.getPoints() np.testing.assert_almost_equal(aA, aP, 12, 'Anisotropy heavily curved not equal', True) # 12 is the number of dec places # test weights aX = np.array([[0.0, -0.3], [-0.44, 0.7], [0.82, -0.01]]) grid.makeGlobalGrid(2, 0, 4, 'level', 'chebyshev') aW = grid.getInterpolationWeightsBatch(aX) aX1 = aX[0,:].reshape([2,]) aX2 = aX[1,:].reshape([2,]) aX3 = aX[2,:].reshape([2,]) aW1 = grid.getInterpolationWeights(aX1) aW2 = grid.getInterpolationWeights(aX2) aW3 = grid.getInterpolationWeights(aX3) aWW = np.row_stack([aW1, aW2, aW3]) np.testing.assert_equal(aW, aWW, "Batch weights", True) grid.makeGlobalGrid(3, 0, 1, 'level', 'chebyshev') aTrans = np.array([[-1.0, -4.0], [2.0, 5.0], [-3.0, 5]]) grid.setDomainTransform(aTrans) aA = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 0.0, 1.0], [0.0, -1.0, 0.0], [0.0, 1.0, 0.0], [-1.0, 0.0, 0.0], [1.0, 0.0, 0.0]]) aB = np.array([[-2.5, 3.5, 1.0], [-2.5, 3.5, -3.0], [-2.5, 3.5, 5.0], [-2.5, 2.0, 1.0], [-2.5, 5.0, 1.0], [-1.0, 3.5, 1.0], [-4.0, 3.5, 1.0]]) np.testing.assert_equal(aB, grid.getPoints(), "Original equal", True) grid.clearDomainTransform() np.testing.assert_equal(aA, grid.getPoints(), "Tansformed equal", True) grid.makeGlobalGrid(3, 0, 1, 'level', 'fejer2') aA = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, -0.707106781186548], [0.0, 0.0, 0.707106781186548], [0.0, -0.707106781186548, 0.0], [0.0, 0.707106781186548, 0.0], [-0.707106781186548, 0.0, 0.0], [0.707106781186548, 0.0, 0.0]]) np.testing.assert_almost_equal(aA, grid.getPoints(), 14, "Original equal", True) grid.setConformalTransformASIN(np.array([4, 6, 3])) aA = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, -0.60890205], [0.0, 0.0, 0.60890205], [0.0, -0.57892643, 0.0], [0.0, 0.57892643, 0.0], [-0.59587172, 0.0, 0.0], [0.59587172, 0.0, 0.0]]) np.testing.assert_almost_equal(aA, grid.getPoints(), 7, "Transformed equal", True) grid.clearConformalTransform() aA = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, -0.707106781186548], [0.0, 0.0, 0.707106781186548], [0.0, -0.707106781186548, 0.0], [0.0, 0.707106781186548, 0.0], [-0.707106781186548, 0.0, 0.0], [0.707106781186548, 0.0, 0.0]]) np.testing.assert_almost_equal(aA, grid.getPoints(), 14, "Original equal", True) # number of points grid = Tasmanian.makeLocalPolynomialGrid(2, 1, 2, 2, "localp") iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 13, "num needed") self.assertEqual(iNL, 0, "num loaded") self.assertEqual(iNP, iNN, "num points") ttc.loadExpN2(grid) iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 0, "num needed") self.assertEqual(iNL, 13, "num loaded") self.assertEqual(iNP, iNL, "num points") grid.setSurplusRefinement(0.10, 0, "classic") iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 8, "num needed") self.assertEqual(iNL, 13, "num loaded") self.assertEqual(iNP, iNL, "num points") grid.setSurplusRefinement(0.05, 0, "classic") iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 16, "num needed") self.assertEqual(iNL, 13, "num loaded") self.assertEqual(iNP, iNL, "num points") ttc.loadExpN2(grid) iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 0, "num needed") self.assertEqual(iNL, 29, "num loaded") self.assertEqual(iNP, iNL, "num points") def checkUpdate(self): ''' Check the update and make working together. ''' grid = Tasmanian.SparseGrid() for iI in range(2): if (iI == 0): sMake = "grid.makeGlobalGrid(2, 1, 2, 'level', 'leja', [2, 1])" sUpda1 = "grid.updateGlobalGrid(2, 'level', [2, 1])" sUpda2 = "grid.updateGlobalGrid(3, 'level', [2, 1])" sUpda3 = "grid.updateGlobalGrid(4, 'ipcurved', [20, 10, 0, 7])" else: sMake = "grid.makeSequenceGrid(2, 1, 2, 'level', 'leja', [2, 1])" sUpda1 = "grid.updateSequenceGrid(2, 'level', [2, 1])" sUpda2 = "grid.updateSequenceGrid(3, 'level', [2, 1])" sUpda3 = "grid.updateSequenceGrid(4, 'ipcurved', [20, 10, 0, 7])" exec(sMake) iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 4, "num needed") self.assertEqual(iNL, 0, "num loaded") self.assertEqual(iNP, iNN, "num points") ttc.loadExpN2(grid) iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 0, "num needed") self.assertEqual(iNL, 4, "num loaded") self.assertEqual(iNP, iNL, "num points") exec(sUpda1) iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 0, "num needed") self.assertEqual(iNL, 4, "num loaded") self.assertEqual(iNP, iNL, "num points") exec(sUpda2) iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 2, "num needed") self.assertEqual(iNL, 4, "num loaded") self.assertEqual(iNP, iNL, "num points") aA = np.array([[0.0, 0.0], [0.0, 1.0], [0.0, -1.0], [1.0, 0.0]]) aP = grid.getPoints() np.testing.assert_equal(aA, aP, "Update Global not equal", True) aP = grid.getLoadedPoints() np.testing.assert_equal(aA, aP, "Update Global not equal", True) aA = np.array([[0.0, np.sqrt(1.0/3.0)], [1.0, 1.0]]) aP = grid.getNeededPoints() np.testing.assert_equal(aA, aP, "Update Global not equal", True) ttc.loadExpN2(grid) iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 0, "num needed") self.assertEqual(iNL, 6, "num loaded") self.assertEqual(iNP, iNL, "num points") exec(sUpda3) iNN = grid.getNumNeeded() iNL = grid.getNumLoaded() iNP = grid.getNumPoints() self.assertEqual(iNN, 1, "num needed") self.assertEqual(iNL, 6, "num loaded") self.assertEqual(iNP, iNL, "num points") aA = np.array([[-1.0, 0.0]]) aP = grid.getNeededPoints() np.testing.assert_equal(aA, aP, "Update Global not equal", True) grid.makeFourierGrid(2, 1, 2, "level") ttc.loadExpN2(grid) grid.updateFourierGrid(3, "level") self.assertEqual(grid.getNumNeeded(), 60, "failed at updateFourierGrid()") def checkDefaults(self): ''' Test that default values are set correctly for alpha/beta/order, empty returns, empty copy. ''' grid = Tasmanian.SparseGrid() for sRule in TasmanianSG.lsTsgLocalRules: grid.makeLocalPolynomialGrid(3, 1, 3, 0, sRule) self.assertEqual(grid.getAlpha(), 0.0, "failed alpha") self.assertEqual(grid.getBeta(), 0.0, "failed beta") self.assertEqual(grid.getOrder(), 0, "failed order") grid.makeLocalPolynomialGrid(3, 1, 3, 1, sRule) self.assertEqual(grid.getAlpha(), 0.0, "failed alpha") self.assertEqual(grid.getBeta(), 0.0, "failed beta") self.assertEqual(grid.getOrder(), 1, "failed order") grid.makeLocalPolynomialGrid(3, 1, 3, 2, sRule) self.assertEqual(grid.getAlpha(), 0.0, "failed alpha") self.assertEqual(grid.getBeta(), 0.0, "failed beta") self.assertEqual(grid.getOrder(), 2, "failed order") grid = Tasmanian.makeWaveletGrid(3, 1, 2, 1) self.assertEqual(grid.getAlpha(), 0.0, "failed alpha") self.assertEqual(grid.getBeta(), 0.0, "failed beta") self.assertEqual(grid.getOrder(), 1, "failed order") grid.makeWaveletGrid(3, 1, 2, 3) self.assertEqual(grid.getAlpha(), 0.0, "failed alpha") self.assertEqual(grid.getBeta(), 0.0, "failed beta") self.assertEqual(grid.getOrder(), 3, "failed order") try: grid.copyGrid([]) self.assertTrue(False, "failed to raise exception on copy grid") except Tasmanian.InputError as TsgError: TsgError.bShowOnExit = False # default alpha/beta and order grid.makeGlobalGrid(2, 0, 2, 'level', 'leja', [2, 1]) self.assertEqual(grid.getAlpha(), 0.0, "failed alpha") self.assertEqual(grid.getBeta(), 0.0, "failed beta") self.assertEqual(grid.getOrder(), -1, "failed order") grid.makeGlobalGrid(1, 0, 4, 'level', 'gauss-hermite', [], 2.0) self.assertEqual(grid.getAlpha(), 2.0, "failed alpha") self.assertEqual(grid.getBeta(), 0.0, "failed beta") self.assertEqual(grid.getOrder(), -1, "failed order") grid.makeGlobalGrid(1, 0, 4, 'level', 'gauss-jacobi', [], 3.0, 2.0) self.assertEqual(grid.getAlpha(), 3.0, "failed alpha") self.assertEqual(grid.getBeta(), 2.0, "failed beta") self.assertEqual(grid.getOrder(), -1, "failed order") grid.makeSequenceGrid(2, 1, 1, 'level', 'leja', [2, 1]) self.assertEqual(grid.getAlpha(), 0.0, "failed alpha") self.assertEqual(grid.getBeta(), 0.0, "failed beta") self.assertEqual(grid.getOrder(), -1, "failed order") # test empty returns dummy_ans = np.empty([0, 0], np.float64) grid_dummy = Tasmanian.SparseGrid() aX = np.empty([0,], np.float64) np.testing.assert_equal(dummy_ans, grid_dummy.getPoints(), "Empty read", True) np.testing.assert_equal(dummy_ans, grid_dummy.getNeededPoints(), "Empty read", True) np.testing.assert_equal(dummy_ans, grid_dummy.getLoadedPoints(), "Empty read", True) dummy_ans = np.empty([0,], np.float64) np.testing.assert_equal(dummy_ans, grid_dummy.getQuadratureWeights(), "Empty read", True) np.testing.assert_equal(dummy_ans, grid_dummy.getInterpolationWeights(aX), "Empty read", True) dummy_ans = np.empty([0, 0], np.float64) aX = np.empty([0, 0], np.float64) np.testing.assert_equal(dummy_ans, grid_dummy.getInterpolationWeightsBatch(aX), "Empty read", True) aX = np.empty([1, 0], np.float64) np.testing.assert_equal(dummy_ans, grid_dummy.getInterpolationWeightsBatch(aX), "Empty read", True) grid.makeGlobalGrid(2, 1, 2, 'level', 'chebyshev') ttc.loadExpN2(grid) dummy_ans = np.empty([0, 1], np.float64) aX = np.empty([0, 2], np.float64) np.testing.assert_equal(dummy_ans, grid.evaluateBatch(aX), "Empty batch eval", True) def checkLevelLimits(self): ''' Check setting level limits. ''' grid = Tasmanian.SparseGrid() # Level Limits grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis', liLevelLimits = [1, 4]) aPoints = grid.getPoints() ttc.checkPoints(aPoints[:,0], lMustHave = [-1.0, 1.0], lMustNotHave = [1.0/np.sqrt(2.0), -1.0/np.sqrt(2.0)]) ttc.checkPoints(aPoints[:,1], lMustHave = [-1.0, 1.0, 1.0/np.sqrt(2.0), -1.0/np.sqrt(2.0)], lMustNotHave = []) ttc.loadExpN2(grid) grid.setAnisotropicRefinement('iptotal', 20, 0, [1, 4]) self.assertTrue(grid.getNumNeeded() > 0, 'did not refine') aPoints = grid.getNeededPoints() ttc.checkPoints(aPoints[:,0], lMustHave = [], lMustNotHave = [1.0/np.sqrt(2.0), -1.0/np.sqrt(2.0)]) grid.makeSequenceGrid(3, 1, 3, 'level', 'leja', liLevelLimits = [3, 2, 1]) aPoints = grid.getPoints() ttc.checkPoints(aPoints[:,0], lMustHave = [0.0, -1.0, 1.0, 1.0/np.sqrt(3.0)], lMustNotHave = []) ttc.checkPoints(aPoints[:,1], lMustHave = [0.0, -1.0, 1.0], lMustNotHave = [1.0/np.sqrt(3.0)]) ttc.checkPoints(aPoints[:,2], lMustHave = [0.0, 1.0], lMustNotHave = [-1.0, 1.0/np.sqrt(3.0)]) ttc.loadExpN2(grid) grid.setAnisotropicRefinement('iptotal', 5, 0) self.assertTrue(grid.getNumNeeded() > 0, 'did not refine') aPoints = grid.getNeededPoints() ttc.checkPoints(aPoints[:,1], lMustHave = [], lMustNotHave = [1.0/np.sqrt(3.0)]) ttc.checkPoints(aPoints[:,2], lMustHave = [], lMustNotHave = [-1.0, 1.0/np.sqrt(3.0)]) grid.clearRefinement() grid.setAnisotropicRefinement('iptotal', 10, 0, [3, 2, 2]) self.assertTrue(grid.getNumNeeded() > 0, 'did not refine') aPoints = grid.getNeededPoints() ttc.checkPoints(aPoints[:,1], lMustHave = [], lMustNotHave = [1.0/np.sqrt(3.0)]) ttc.checkPoints(aPoints[:,2], lMustHave = [1.0], lMustNotHave = [1.0/np.sqrt(3.0)]) grid.clearRefinement() grid.setSurplusRefinement(1.E-8, 0, '', [3, 2, 1]) self.assertTrue(grid.getNumNeeded() > 0, 'did not refine') aPoints = grid.getNeededPoints() ttc.checkPoints(aPoints[:,1], lMustHave = [], lMustNotHave = [1.0/np.sqrt(3.0)]) ttc.checkPoints(aPoints[:,2], lMustHave = [], lMustNotHave = [-1.0, 1.0/np.sqrt(3.0)]) # check that nodes from level 2 (+-0.5) and 3 (+-0.25, +-0.75) appear only in the proper dimension grid.makeLocalPolynomialGrid(3, 1, 3, 1, 'localp', [1, 2, 3]) aPoints = grid.getPoints() ttc.checkPoints(aPoints[:,0], lMustHave = [0.0, -1.0, 1.0], lMustNotHave = [0.5, -0.5, -0.75, -0.25, 0.25, 0.75]) ttc.checkPoints(aPoints[:,1], lMustHave = [0.0, -1.0, 1.0, 0.5, -0.5], lMustNotHave = [-0.75, -0.25, 0.25, 0.75]) ttc.checkPoints(aPoints[:,2], lMustHave = [0.0, -1.0, 1.0, 0.5, -0.5, -0.75, -0.25, 0.25, 0.75], lMustNotHave = []) ttc.loadExpN2(grid) grid.setSurplusRefinement(1.E-8, 0, 'classic') self.assertTrue(grid.getNumNeeded() > 0, 'did not refine') aPoints = grid.getNeededPoints() ttc.checkPoints(aPoints[:,0], lMustHave = [], lMustNotHave = [0.5, -0.5, -0.75, -0.25, 0.25, 0.75]) ttc.checkPoints(aPoints[:,1], lMustHave = [], lMustNotHave = [-0.75, -0.25, 0.25, 0.75]) ttc.checkPoints(aPoints[:,2], lMustHave = [], lMustNotHave = []) grid.clearRefinement() grid.setSurplusRefinement(1.E-8, 0, 'classic', [2, 2, 3]) aPoints = grid.getNeededPoints() ttc.checkPoints(aPoints[:,0], lMustHave = [0.5, -0.5], lMustNotHave = [-0.75, -0.25, 0.25, 0.75]) ttc.checkPoints(aPoints[:,1], lMustHave = [], lMustNotHave = [-0.75, -0.25, 0.25, 0.75]) grid.makeWaveletGrid(2, 1, 3, 1, [0, 2]) aPoints = grid.getPoints() ttc.checkPoints(aPoints[:,0], lMustHave = [0.0, -1.0, 1.0], lMustNotHave = [-0.5, 0.5]) ttc.checkPoints(aPoints[:,1], lMustHave = [0.0, -1.0, 1.0, -0.5, 0.5, -0.75, -0.25, 0.25, 0.75], lMustNotHave = [-0.125, 0.125]) ttc.loadExpN2(grid) grid.setSurplusRefinement(1.E-8, 0, 'classic') # grid is effectively full tensor, cannot refine within the level limits self.assertTrue((grid.getNumNeeded() == 0), 'added points even though it should not have'); grid.setSurplusRefinement(1.E-8, 0, 'classic', [1, 2]) aPoints = grid.getNeededPoints() ttc.checkPoints(aPoints[:,0], lMustHave = [0.5, -0.5], lMustNotHave = [-0.75, -0.25, 0.25, 0.75]) ttc.checkPoints(aPoints[:,1], lMustHave = [], lMustNotHave = [-0.125, 0.125]) # level limits I/O grid.makeLocalPolynomialGrid(3, 1, 3, 1, 'localp', [1, 2, 3]) aLimits = grid.getLevelLimits() np.testing.assert_almost_equal(aLimits, np.array([1, 2, 3]), 14, "Could not read level limits", True) grid.clearLevelLimits() aLimits = grid.getLevelLimits() np.testing.assert_almost_equal(aLimits, np.array([-1, -1, -1]), 14, "Could not read level limits", True) def performMakeUpdateTests(self): self.checkPathsVersions() self.checkMakeAgainstKnown() self.checkUpdate() self.checkDefaults() self.checkLevelLimits() TASMANIAN-8.1/InterfacePython/testMisc.py000066400000000000000000000200301470551176200201470ustar00rootroot00000000000000import unittest import TasmanianSG import os import numpy as np import testCommon ttc = testCommon.TestTasCommon() class TestTasClass(unittest.TestCase): ''' Miscelaneous tests that don't quite fit in other categories. ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def checkPolynomialSpace(self): ''' Construct grids with specific parameters and check the polynomial space against known (pen-and-paper) exact spaces. ''' grid = TasmanianSG.TasmanianSparseGrid() aA = np.array([[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2], [3, 0], [4, 0]]) grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis') aP = grid.getGlobalPolynomialSpace(True) np.testing.assert_equal(aP, aA, "poly space mismatch", True) aA = np.array([[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [2, 0], [2, 1], [2, 2], [2, 3], [3, 0], [3, 1], [3, 2], [3, 3], [4, 0], [4, 1], [5, 0], [5, 1]]) grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis') aP = grid.getGlobalPolynomialSpace(False) np.testing.assert_equal(aP, aA, "poly space mismatch", True) aA = np.array([[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [2, 0]]) grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja') aP = grid.getGlobalPolynomialSpace(True) np.testing.assert_equal(aP, aA, "poly space mismatch", True) grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja') aP = grid.getGlobalPolynomialSpace(False) np.testing.assert_equal(aP, aA, "poly space mismatch", True) aA = np.array([[0, 0], [0, 1], [0, 2], [0, 3], [1, 0], [1, 1], [1, 2], [1, 3], [2, 0], [2, 1], [3, 0], [3, 1]]) grid.makeGlobalGrid(2, 1, 1, 'level', 'leja-odd') aP = grid.getGlobalPolynomialSpace(False) np.testing.assert_equal(aP, aA, "poly space mismatch", True) grid.makeSequenceGrid(2, 1, 2, 'level', 'leja') aP = grid.getGlobalPolynomialSpace(False) np.testing.assert_equal(aP, aA, "poly space mismatch", True) def checkPlotting(self): ''' If matplotlib is available and there is an active display, then make plot commands but do not show the final plots. If matplotlib is missing, check the exceptions. ''' grid = TasmanianSG.TasmanianSparseGrid() if (TasmanianSG.bTsgPlotting): if ((os.name == "posix") and (os.environ.get('DISPLAY') is None)): print("NOTE: there is no display, cannot run plotting tests.") return grid.makeGlobalGrid(2, 1, 20, 'level', 'leja') ttc.loadExpN2(grid) grid.plotResponse2D() grid.plotPoints2D() grid.makeGlobalGrid(2, 1, 0, 'level', 'leja') ttc.loadExpN2(grid) grid.plotResponse2D() grid.plotPoints2D() grid.makeGlobalGrid(3, 1, 3, 'level', 'leja') try: grid.plotPoints2D() self.assertTrue(False, "failed to flag plot exception when when using a grid with other than 2D") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "plotPoints2D", "error raising exception for plotPoints2D() using test\n Error.sVariable = '{0:1s}'".format(TSGError.sVariable)) try: grid.plotResponse2D() self.assertTrue(False, "failed to flag plot exception when when using a grid with other than 2D") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "plotResponse2D", "error raising exception for plotResponse2D() using test\n Error.sVariable = '{0:1s}'".format(TSGError.sVariable)) grid.makeGlobalGrid(2, 2, 2, 'level', 'leja') try: grid.plotResponse2D(iOutput = -1) self.assertTrue(False, "failed to flag plot exception when when using wrong output") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "iOutput", "error raising exception for plotResponse2D() using test\n Error.sVariable = '{0:1s}'".format(TSGError.sVariable)) try: grid.plotResponse2D(iOutput = 3) self.assertTrue(False, "failed to flag plot exception when when using wrong output") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "iOutput", "error raising exception for plotResponse2D() using test\n Error.sVariable = '{0:1s}'".format(TSGError.sVariable)) try: grid.plotResponse2D(iNumDim0 = -1) self.assertTrue(False, "failed to flag plot exception when when using wrong output") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "iNumDim0", "error raising exception for plotResponse2D() using test\n Error.sVariable = '{0:1s}'".format(TSGError.sVariable)) try: grid.plotResponse2D(iNumDim1 = -1) self.assertTrue(False, "failed to flag plot exception when when using wrong output") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "iNumDim1", "error raising exception for plotResponse2D() using test\n Error.sVariable = '{0:1s}'".format(TSGError.sVariable)) else: grid.makeGlobalGrid(2, 1, 3, 'level', 'leja') ttc.loadExpN2(grid) try: grid.plotResponse2D() self.assertTrue(False, "failed to flag plotexception when missing matplotlib") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "plotResponse2D", "error raising exception for plotResponse2D() using test\n Error.sVariable = '{0:1s}'".format(TSGError.sVariable)) try: grid.plotPoints2D() self.assertTrue(False, "failed to flag plot exception when missing matplotlib") except TasmanianSG.TasmanianInputError as TSGError: TSGError.bShowOnExit = False self.assertEqual(TSGError.sVariable, "plotPoints2D", "error raising exception for plotPoints2D() using test\n Error.sVariable = '{0:1s}'".format(TSGError.sVariable)) def checkDerivatives(self): ''' Check the consistency of derivatives in terms of dimensions and ordering. ''' func1 = lambda x : 2.0 * x[0] * x[0] + x[1] * x[1] / 2.0 grid1 = TasmanianSG.makeGlobalGrid(2, 1, 4, "iptotal", "gauss-legendre") points1 = grid1.getNeededPoints() values1 = np.resize(np.apply_along_axis(func1, 1, points1), [grid1.getNumNeeded(), 1]) grid1.loadNeededValues(values1) grad1 = grid1.differentiate(np.array([3.0, 4.0])) self.assertEqual(grad1.shape, (2,)) self.assertTrue(np.allclose(grad1, np.array([12.0, 4.0]))) func2 = lambda x : [2.0 * x[0] * x[0] + x[1] * x[1] / 2.0 + x[2] * x[2], x[0] * x[1] * x[2]] grid2 = TasmanianSG.makeGlobalGrid(3, 2, 4, "iptotal", "gauss-legendre") points2 = grid2.getNeededPoints() values2 = np.resize(np.apply_along_axis(func2, 1, points2), [grid2.getNumNeeded(), 2]) grid2.loadNeededValues(values2) grad2 = grid2.differentiate(np.array([1.0, 2.0, 3.0])) self.assertEqual(grad2.shape, (2, 3)) self.assertTrue(np.allclose(grad2, np.array([[4.0, 2.0, 6.0], [6.0, 3.0, 2.0]]))) def performMiscTests(self): self.checkPolynomialSpace() self.checkPlotting() self.checkDerivatives() TASMANIAN-8.1/InterfacePython/testOptimization.py000066400000000000000000000205201470551176200217460ustar00rootroot00000000000000# Copyright (c) 2022, Miroslav Stoyanov & Weiwei Kong # # This file is part of # Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions # and the following disclaimer in the documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse # or promote products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND # IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF # THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL # ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES # RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING # FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. import unittest import Tasmanian DREAM = Tasmanian.DREAM Opt = Tasmanian.Optimization import os import numpy as np import testCommon ttc = testCommon.TestTasCommon() class TestTasClass(unittest.TestCase): ''' Tests for the Tasmanian Optimization python bindings module ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def checkParticleSwarmState(self): iNumDimensions = 2 iNumParticles = 5 # Initialization tests. state = Opt.ParticleSwarmState(iNumDimensions, iNumParticles) self.assertEqual(iNumDimensions, state.getNumDimensions()) self.assertEqual(iNumParticles, state.getNumParticles()) self.assertFalse(state.isPositionInitialized()) self.assertFalse(state.isVelocityInitialized()) self.assertFalse(state.isBestPositionInitialized()) self.assertFalse(state.isCacheInitialized()) # Loading/Unloading tests. pp = np.arange(iNumParticles * iNumDimensions, dtype=np.float64).reshape(iNumParticles, iNumDimensions) state.setParticlePositions(pp) self.assertTrue(state.isPositionInitialized()) np.testing.assert_array_equal(pp, state.getParticlePositions()) pv = np.arange(iNumParticles * iNumDimensions, dtype=np.float64).reshape(iNumParticles, iNumDimensions) state.setParticleVelocities(pv) np.testing.assert_array_equal(pv, state.getParticleVelocities()) bpp = np.arange((iNumParticles+1) * iNumDimensions, dtype=np.float64).reshape(iNumParticles+1, iNumDimensions) state.setBestParticlePositions(bpp) self.assertTrue(state.isBestPositionInitialized()) np.testing.assert_array_equal(bpp, state.getBestParticlePositions()) state.clearBestParticles() self.assertFalse(state.isBestPositionInitialized()) np.testing.assert_array_equal(np.zeros([iNumParticles + 1, iNumDimensions]), state.getBestParticlePositions()) # Generation tests. state = Opt.ParticleSwarmState(iNumDimensions, iNumParticles) state.initializeParticlesInsideBox(np.array([-1.0, 1.0]), np.array([2.0, 3.0]), random01=DREAM.RandomGenerator(sType="default", iSeed=777)) self.assertTrue(state.isPositionInitialized()) self.assertTrue(state.isVelocityInitialized()) pp = state.getParticlePositions() self.assertTrue(np.all((-1.0 <= pp[:,0]) & (pp[:,0] <= 2.0))) self.assertTrue(np.all((1.0 <= pp[:,1]) & (pp[:,1] <= 3.0))) def checkParticleSwarm(self): iNumDimensions = 2 iNumParticles = 50 state = Opt.ParticleSwarmState(iNumDimensions, iNumParticles) state.initializeParticlesInsideBox(np.array([-3.0, -2.0]), np.array([3.0, 2.0]), random01=DREAM.RandomGenerator(sType="default", iSeed=777)) # Six-hump-camel function. shc = lambda x : (4 - 2.1*x[0]*x[0] + x[0]*x[0]*x[0]*x[0]/3)*x[0]*x[0] + x[0]*x[1] + (-4.0 + 4.0*x[1]*x[1])*x[1]*x[1] f = lambda x_batch : np.apply_along_axis(shc, 1, x_batch) inside = lambda x : bool((-3 <= x[0]) and (x[0] <= 3) and (-2 <= x[1]) and (x[1] <= 2)) # Main call + tests. Opt.ParticleSwarm(f, inside, 0.5, 2, 2, 1, state, random01=DREAM.RandomGenerator(sType="default", iSeed=777)) self.assertTrue(state.isCacheInitialized()) state.clearCache() self.assertFalse(state.isCacheInitialized()) iNumIterations = 200 Opt.ParticleSwarm(f, inside, 0.5, 2, 2, iNumIterations, state) self.assertTrue(np.allclose(np.array([-0.08984201368301331, +0.7126564032704135]), state.getBestPosition()) or np.allclose(np.array([+0.08984201368301331, -0.7126564032704135]), state.getBestPosition()) ) def checkGradientDescentState(self): x0 = np.array([0.0, 1.0]) stepsize = 2.0; # Initialization tests. state = Opt.GradientDescentState(x0, stepsize) self.assertEqual(len(x0), state.getNumDimensions()) np.testing.assert_array_equal(x0, state.getX()) self.assertEqual(stepsize, state.getAdaptiveStepsize()) # Loading/Unloading tests. x1 = np.array([3.0, 4.0]) state.setX(x1) np.testing.assert_array_equal(x1, state.getX()) state.setAdaptiveStepsize(5.0) self.assertEqual(5.0, state.getAdaptiveStepsize()) def checkGradientDescent(self): func = lambda x : 2.0 * x[0] * x[0] + x[1] * x[1] / 2.0 grad = lambda x : np.array([4.0 * x[0], x[1]]) lambda0 = 3.0 xBar = np.array([0.0, 0.0]) xBarConstr = np.array([-0.5, 0.5]) tol = 1E-6 iter_limit = 100 # Main call + tests. state = Opt.GradientDescentState(np.array([-1.0, 1.0]), lambda0) result = Opt.GradientDescent(grad, 1/4.0, iter_limit, tol, state) self.assertLessEqual(result['performed_iterations'], iter_limit) self.assertTrue(np.allclose(xBar, state.getX(), atol=tol * 10)) self.assertEqual(lambda0, state.getAdaptiveStepsize()) state = Opt.GradientDescentState(np.array([-1.0, 1.0]), lambda0) result = Opt.AdaptiveGradientDescent(func, grad, 1.25, 1.25, iter_limit, tol, state) self.assertLessEqual(result['performed_iterations'], iter_limit) self.assertTrue(np.allclose(xBar, state.getX(), atol=tol * 10)) proj = lambda x : np.array([min(max(-3.0, x[0]), -0.5), min(max(0.5, x[1]), 3.0)]) state = Opt.GradientDescentState(np.array([-2.0, 2.0]), lambda0) result = Opt.AdaptiveProjectedGradientDescent(func, grad, proj, 1.25, 1.25, iter_limit, tol, state) self.assertLessEqual(result['performed_iterations'], iter_limit) self.assertTrue(np.allclose(xBarConstr, state.getX(), atol=tol)) def performOptTests(self): self.checkParticleSwarmState() self.checkParticleSwarm() self.checkGradientDescentState() self.checkGradientDescent() if __name__ == "__main__": tester = TestTasClass() tester.performOptTests() TASMANIAN-8.1/InterfacePython/testRefinement.py000066400000000000000000000302071470551176200213570ustar00rootroot00000000000000import unittest import TasmanianSG import numpy as np from random import shuffle import testCommon ttc = testCommon.TestTasCommon() class TestTasClass(unittest.TestCase): ''' Test the refinement capabilities: * set different refinements * estimate anisotropic coefficients * read/write refinements ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def checkSetClear(self): ''' Set refinement and clear refinement ''' grid = TasmanianSG.TasmanianSparseGrid() grid.makeLocalPolynomialGrid(2, 1, 2, 1, 'semi-localp') ttc.loadExpN2(grid) self.assertEqual(grid.getNumNeeded(), 0, "num needed") grid.setSurplusRefinement(0.0001, 0, 'classic') self.assertTrue((grid.getNumNeeded() > 0), "num needed") grid.clearRefinement() self.assertEqual(grid.getNumNeeded(), 0, "num needed") def checkAnisoCoeff(self): ''' Check anisotropic coefficients ''' grid = TasmanianSG.TasmanianSparseGrid() grid.makeGlobalGrid(2, 1, 9, 'level', 'rleja') aP = grid.getPoints() aV = np.exp(aP[:,0] + aP[:,1]**2) grid.loadNeededPoints(aV.reshape([aP.shape[0], 1])) aC = grid.estimateAnisotropicCoefficients('iptotal', 0) self.assertEqual(len(aC.shape), 1, 'dimensions of the estimated anisotropic weight') self.assertEqual(aC.shape[0], 2, 'dimensions of the estimated anisotropic weight') self.assertLess(np.abs(float(aC[0]) / float(aC[1]) - 2.0), 0.2, 'wrong anisotropic weights estimated') aC = grid.estimateAnisotropicCoefficients('ipcurved', 0) self.assertEqual(len(aC.shape), 1, 'dimensions of the estimated anisotropic weight') self.assertEqual(aC.shape[0], 4, 'dimensions of the estimated anisotropic weight') self.assertLess(np.abs(float(aC[0]) / float(aC[1]) - 2.0), 0.2, 'wrong anisotropic weights estimated, alpha curved') self.assertLess(aC[2], 0.0, 'wrong anisotropic weights estimated, beta 1') self.assertLess(aC[3], 0.0, 'wrong anisotropic weights estimated, beta 2') def checkLocalpSurplus(self): ''' Check surplus refinement for local polynomial grids ''' grid = TasmanianSG.TasmanianSparseGrid() grid.makeLocalPolynomialGrid(2, 1, 4, 1, 'semi-localp') ttc.loadExpN2(grid) aPoints = grid.getPoints() aScale = np.array([[1.0 if aPoints[i,0] > 0.0 else 0.0] for i in range(aPoints.shape[0])]) grid.setSurplusRefinement(1.E-9, 0, 'classic', [], aScale) aNeeded = grid.getNeededPoints() for iI in range(aNeeded.shape[0]): self.assertLess(0.0, aNeeded[iI, 0], 'wrong set of needed points after rescaling') def checkFileIO(self): ''' Read/Write regular refinement. ''' grid = TasmanianSG.TasmanianSparseGrid() sRefinementIOGrids = ["grid.makeGlobalGrid(2, 1, 2, 'level', 'clenshaw-curtis')", "grid.makeSequenceGrid(2, 1, 2, 'level', 'rleja')"] for sTest in sRefinementIOGrids: exec(sTest) ttc.loadExpN2(grid) grid.setAnisotropicRefinement('iptotal', 20, 0) self.assertTrue(grid.getNumNeeded() > 0, 'did not refine') gridB = TasmanianSG.TasmanianSparseGrid() gridB.copyGrid(grid) ttc.compareGrids(grid, gridB) grid.write("refTestFlename.grid", bUseBinaryFormat = True) gridB.makeLocalPolynomialGrid(1, 1, 0, 1) gridB.read("refTestFlename.grid") ttc.compareGrids(grid, gridB) grid.write("refTestFlename.grid", bUseBinaryFormat = False) gridB.makeLocalPolynomialGrid(1, 1, 0, 1) gridB.read("refTestFlename.grid") ttc.compareGrids(grid, gridB) def checkConstruction(self): ''' Test read/write when using construction. ''' llTest = ["gridA.makeGlobalGrid(3, 2, 2, 'level', 'clenshaw-curtis'); gridB.makeGlobalGrid(3, 2, 2, 'level', 'clenshaw-curtis')", "gridA.makeSequenceGrid(3, 2, 4, 'level', 'leja'); gridB.makeSequenceGrid(3, 2, 4, 'level', 'leja')", "gridA.makeLocalPolynomialGrid(3, 2, 2); gridB.makeLocalPolynomialGrid(3, 2, 2)", "gridA.makeWaveletGrid(3, 2, 2); gridB.makeWaveletGrid(3, 2, 2)", "gridA.makeFourierGrid(3, 2, 2, 'level'); gridB.makeFourierGrid(3, 2, 2, 'level')",] for sMakeGrids in llTest: for sFormat in [False, True]: # test binary and ascii format gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() gridC = TasmanianSG.TasmanianSparseGrid() exec(sMakeGrids) gridA.beginConstruction() gridB.beginConstruction() #gridA.printStats() gridB.write("testSave", bUseBinaryFormat = sFormat) gridB.makeSequenceGrid(1, 1, 0, "level", "rleja") # clean the grid gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridC.copyGrid(gridA) ttc.compareGrids(gridA, gridC) for t in range(5): # use 5 iterations if (gridA.isLocalPolynomial() or gridA.isWavelet()): aPointsA = gridA.getCandidateConstructionPointsSurplus(1.E-4, "fds") aPointsB = gridB.getCandidateConstructionPointsSurplus(1.E-4, "fds") aPointsC = gridC.getCandidateConstructionPointsSurplus(1.E-4, "fds") else: aPointsA = gridA.getCandidateConstructionPoints("level", 0) aPointsB = gridB.getCandidateConstructionPoints("level", 0) aPointsC = gridC.getCandidateConstructionPoints("level", 0) np.testing.assert_almost_equal(aPointsA, aPointsB, decimal=11) np.testing.assert_almost_equal(aPointsA, aPointsC, decimal=11) iNumPoints = int(aPointsA.shape[0] / 2) if (iNumPoints > 32): iNumPoints = 32 # use the first samples (up to 32) and shuffle the order # add one of the samples further in the list liSamples = list(range(iNumPoints + 1)) shuffle(liSamples) for iI in range(len(liSamples)): if (liSamples[iI] == iNumPoints): liSamples[iI] = iNumPoints + 1 #liSamples = map(lambda i: i if i < iNumPoints else iNumPoints + 1, liSamples) for iI in liSamples: # compute and load the samples aPoint = aPointsA[iI, :] aValue = np.array([np.exp(aPoint[0] + aPoint[1]), 1.0 / ((aPoint[0] - 1.3) * (aPoint[1] - 1.6) * (aPoint[2] - 2.0))]) gridA.loadConstructedPoint(aPoint, aValue) gridB.loadConstructedPoint(aPoint, aValue) gridC.loadConstructedPoint(aPoint, aValue) # using straight construction or read/write should produce the same result ttc.compareGrids(gridA, gridC) gridB.write("testSave", bUseBinaryFormat = sFormat) gridB.makeSequenceGrid(1, 1, 0, "level", "rleja") gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridC.copyGrid(gridA) ttc.compareGrids(gridA, gridC) gridA.finishConstruction() gridB.finishConstruction() gridB.write("testSave", bUseBinaryFormat = sFormat) gridB.makeSequenceGrid(1, 1, 0, "level", "rleja") gridB.read("testSave") ttc.compareGrids(gridA, gridB) gridC.copyGrid(gridA) ttc.compareGrids(gridA, gridC) # check multi-point load gridA = TasmanianSG.TasmanianSparseGrid() gridA.makeLocalPolynomialGrid(3, 2, 4); ttc.loadExpN2(gridA) gridB = TasmanianSG.TasmanianSparseGrid() gridB.makeLocalPolynomialGrid(3, 2, 0) gridB.beginConstruction() aX = gridA.getPoints() aY = gridA.evaluateBatch(aX) gridB.loadConstructedPoint(aX, aY) gridB.finishConstruction() ttc.compareGrids(gridA, gridB) # check some mem-leaks and crashes (correctness is elsewhere) gridA = TasmanianSG.TasmanianSparseGrid() gridA.makeLocalPolynomialGrid(2, 5, 0) gridA.beginConstruction() gridA.loadConstructedPoint(np.empty([0, 2]), np.empty([0, 5])) # empty input, check for crash gridA.makeLocalPolynomialGrid(2, 1, 1) gridA.loadNeededPoints(np.ones([5, 1])) gridA.beginConstruction() aPoints = gridA.getCandidateConstructionPointsSurplus(1.E-4, "classic") # should generate empty output np.testing.assert_almost_equal(aPoints, np.empty([0, 0]), 14, "failed to generate empty list of construction points", True) gridA.makeLocalPolynomialGrid(2, 1, 0) gridA.loadNeededPoints(np.ones([1, 1])) gridA.beginConstruction() aPoints = gridA.getCandidateConstructionPointsSurplus(1.E-4, "classic", 0, [], np.array([[1.E-6]])) # should generate empty output np.testing.assert_almost_equal(aPoints, np.empty([0, 0]), 14, "failed to generate empty list of construction points", True) gridA.makeGlobalGrid(2, 1, 1, "tensor", "clenshaw-curtis") gridA.loadNeededPoints(np.ones([9, 1])) gridA.beginConstruction() aPoints = gridA.getCandidateConstructionPoints("ipcurved", [5, 5, 2, 2], [1, 1]) # should generate empty output np.testing.assert_almost_equal(aPoints, np.empty([0, 0]), 14, "failed to generate empty list of construction points", True) def checkRemovePoints(self): ''' tests removePointsByHierarchicalCoefficient() ''' grid = TasmanianSG.makeLocalPolynomialGrid(2, 1, 1) aPoints = grid.getNeededPoints() grid.loadNeededValues(np.exp(-aPoints[:,0]**2 -0.5*aPoints[:,1]**2).reshape((grid.getNumNeeded(), 1))) reduced = TasmanianSG.TasmanianSparseGrid() reduced.copyGrid(grid) reduced.removePointsByHierarchicalCoefficient(0.6) self.assertEqual(reduced.getNumPoints(), 3, "failed to remove points with threshold 0.6") np.testing.assert_almost_equal(reduced.getLoadedPoints(), np.array([[0.0, 0.0], [-1.0, 0.0], [1.0, 0.0]]), 14, "failed reduce 1", True) reduced.copyGrid(grid) reduced.removePointsByHierarchicalCoefficient(0.7) self.assertEqual(reduced.getNumPoints(), 1, "failed to remove points with threshold 0.7") np.testing.assert_almost_equal(reduced.getLoadedPoints(), np.array([[0.0, 0.0]]), 14, "failed reduce 2", True) reduced.copyGrid(grid) reduced.removePointsByHierarchicalCoefficient(0.0, iNumKeep = 3) self.assertEqual(reduced.getNumPoints(), 3, "failed to remove points down to 3") np.testing.assert_almost_equal(reduced.getLoadedPoints(), np.array([[0.0, 0.0], [-1.0, 0.0], [1.0, 0.0]]), 14, "failed reduce 3", True) reduced.copyGrid(grid) reduced.removePointsByHierarchicalCoefficient(0.0, iNumKeep = 1) self.assertEqual(reduced.getNumPoints(), 1, "failed to remove points down to 1") np.testing.assert_almost_equal(reduced.getLoadedPoints(), np.array([[0.0, 0.0]]), 14, "failed reduce 4", True) reduced.copyGrid(grid) reduced.removePointsByHierarchicalCoefficient(0.0, aScaleCorrection = np.array([[1.0], [1.0], [1.0], [0.1], [0.1]]), iNumKeep = 3) self.assertEqual(reduced.getNumPoints(), 3, "failed to remove corrected points") np.testing.assert_almost_equal(reduced.getLoadedPoints(), np.array([[0.0, 0.0], [0.0, -1.0], [0.0, 1.0]]), 14, "failed reduce 5", True) def performRefinementTest(self): self.checkSetClear() self.checkAnisoCoeff() self.checkLocalpSurplus() self.checkFileIO() self.checkConstruction() self.checkRemovePoints() TASMANIAN-8.1/InterfacePython/testTSG.py000077500000000000000000000045641470551176200177320ustar00rootroot00000000000000#!/usr/bin/env python3 # The hash-bang is used only but the GNU Make build system # The CMake build system ignores the hash-bang and uses the executable from find_package(). import unittest import TasmanianSG import math import sys, os import numpy as np from random import uniform from ctypes import cdll import testCommon import testBasicIO import testAcceleration import testExceptions import testMakeUpdate import testRefinement import testUnstructuredData import testMisc import testAddons import testDream import testOptimization grid = TasmanianSG.TasmanianSparseGrid() ttc = testCommon.TestTasCommon() # python-coverage run testTSG.py # python-coverage html # python-coverage report class TestTasmanian(unittest.TestCase): def testBasicIO(self): print("\nTesting core I/O test") tester = testBasicIO.TestTasClass() tester.performIOTest() def testAcceleratedEvaluate(self): print("\nTesting accelerated evaluate consistency") tester = testAcceleration.TestTasClass() tester.performAccelerationTest() def testBasicException(self): print("\nTesting error handling") tester = testExceptions.TestTasClass() tester.performExceptionsTest() def testAMakeUpdate(self): print("\nTesting core make/update grid") tester = testMakeUpdate.TestTasClass() tester.performMakeUpdateTests() def testBRefinement(self): print("\nTesting core refine grid") tester = testRefinement.TestTasClass() tester.performRefinementTest() def testCUnsructuredData(self): print("\nTesting core learning from random samples") tester = testUnstructuredData.TestTasClass() tester.performUnstructuredDataTests() def testZMisc(self): print("\nTesting plotting and other misc") tester = testMisc.TestTasClass() tester.performMiscTests() def testAddons(self): print("\nTesting addon wrappers") tester = testAddons.TestTasClass() tester.performAddonTests() def testDream(self): print("\nTesting DREAM wrappers") tester = testDream.TestTasClass() tester.performDreamTests() def testOptimization(self): print("\nTesting Optimization Functions") tester = testOptimization.TestTasClass() tester.performOptTests() if __name__ == '__main__': unittest.main() TASMANIAN-8.1/InterfacePython/testUnstructuredData.py000066400000000000000000000300111470551176200225550ustar00rootroot00000000000000import unittest import TasmanianSG import numpy as np import testCommon # needed to compare grids after merge refinement ttc = testCommon.TestTasCommon() class TestTasClass(unittest.TestCase): ''' Test methods for directly setting hierarchical matrices and coeffs, useful to build grids from unstructured/random data. ''' def __init__(self): unittest.TestCase.__init__(self, "testNothing") def testNothing(self): pass def checkAgainstKnown(self): ''' Check hierarchical functions against known (pen-and-paper) solutions. ''' grid = TasmanianSG.TasmanianSparseGrid() # evalHierarchicalBasis (all done in batch), dense mode grid.makeLocalPolynomialGrid(2, 2, 1, 1, 'localp') aT = np.empty([0,2], np.float64) np.testing.assert_equal(aT, grid.getHierarchicalCoefficients(), "coeff mismatch", True) grid.makeLocalPolynomialGrid(2, 0, 1, 1, 'localp') aT = np.empty([0,0], np.float64) np.testing.assert_equal(aT, grid.getHierarchicalCoefficients(), "coeff mismatch", True) grid.makeLocalPolynomialGrid(2, 2, 1, 1, 'localp') aPoints = grid.getPoints() aV = np.column_stack([np.exp(2.0 * aPoints[:,0] + aPoints[:,1]), np.sin(3.0 * aPoints[:,0] + aPoints[:,1])]) grid.loadNeededPoints(aV) aS = grid.getHierarchicalCoefficients() aT = np.array([[1.0, 0.0], [np.exp(-1.0)-1.0, np.sin(-1.0)], [np.exp(1.0)-1.0, np.sin(1.0)], [np.exp(-2.0)-1.0, np.sin(-3.0)], [np.exp(2.0)-1.0, np.sin(3.0)]]) np.testing.assert_almost_equal(aS, aT, 14, "Surplusses equal", True) grid.makeGlobalGrid(3, 1, 4, 'level', 'fejer2') aPoints = grid.getPoints() aVan = grid.evaluateHierarchicalFunctions(aPoints) aIdentity = np.zeros([grid.getNumPoints(), grid.getNumPoints()], np.float64) for iI in range(grid.getNumPoints()): aIdentity[iI,iI] = 1.0 np.testing.assert_almost_equal(aVan, aIdentity, 14, "evaluateHierarchicalFunctions", True) grid.makeGlobalGrid(2, 1, 1, 'level', 'clenshaw-curtis') aPoints = np.array([[0.33, 0.25], [-0.27, 0.39], [0.97, -0.76], [-0.44, 0.21], [-0.813, 0.03], [-0.666, 0.666]]) f0 = (1.0 - aPoints[:,0]**2) + (1.0 - aPoints[:,1]**2) - 1.0 f1 = 0.5 * aPoints[:,1] * (aPoints[:,1] - 1.0) f2 = 0.5 * aPoints[:,1] * (aPoints[:,1] + 1.0) f3 = 0.5 * aPoints[:,0] * (aPoints[:,0] - 1.0) f4 = 0.5 * aPoints[:,0] * (aPoints[:,0] + 1.0) aResult = np.column_stack([f0, f1, f2, f3, f4]) aVan = grid.evaluateHierarchicalFunctions(aPoints) np.testing.assert_almost_equal(aVan, aResult, 14, "evaluateHierarchicalFunctions", True) grid.makeSequenceGrid(2, 1, 2, 'level', 'leja') aPoints = np.array([[0.33, 0.25], [-0.27, 0.39], [0.97, -0.76], [-0.44, 0.21], [-0.813, 0.03], [-0.666, 0.666]]) f0 = np.ones([aPoints.shape[0],]) f1 = aPoints[:,1] f2 = 0.5 * aPoints[:,1] * (aPoints[:,1] - 1.0) f3 = aPoints[:,0] f4 = aPoints[:,0] * aPoints[:,1] f5 = 0.5 * aPoints[:,0] * (aPoints[:,0] - 1.0) aResult = np.column_stack([f0, f1, f2, f3, f4, f5]) aVan = grid.evaluateHierarchicalFunctions(aPoints) np.testing.assert_almost_equal(aVan, aResult, 14, "evaluateHierarchicalFunctions", True) grid.makeLocalPolynomialGrid(2, 1, 1, 1, 'localp') aPoints = np.array([[0.33, 0.25], [-0.27, 0.39], [0.97, -0.76], [-0.44, 0.21], [-0.813, 0.03], [-0.666, 0.666]]) f0 = np.ones([aPoints.shape[0],]) f1 = -aPoints[:,1] f2 = np.copy(aPoints[:,1]) f3 = -aPoints[:,0] f4 = np.copy(aPoints[:,0]) for iI in range(aPoints.shape[0]): if (aPoints[iI,1] > 0.0): f1[iI] = 0.0 if (aPoints[iI,1] < 0.0): f2[iI] = 0.0 if (aPoints[iI,0] > 0.0): f3[iI] = 0.0 if (aPoints[iI,0] < 0.0): f4[iI] = 0.0 aResult = np.column_stack([f0, f1, f2, f3, f4]) aVan = grid.evaluateHierarchicalFunctions(aPoints) np.testing.assert_almost_equal(aVan, aResult, 14, "evaluateHierarchicalFunctions", True) grid.makeFourierGrid(2, 1, 1, "level") aPoints = np.array([[0.25, 0.5]]); aResult = np.array([[1.0 + 0.0 * 1j, -1.0 + 0.0 * 1j, -1.0 + 0.0 * 1j, 0.0 - 1.0 * 1j, 0.0 + 1.0 * 1j]]) aVan = grid.evaluateHierarchicalFunctions(aPoints) np.testing.assert_almost_equal(aVan, aResult, 14, "evaluateHierarchicalFunctions", True) # sparse hierarchical functions pSparse = TasmanianSG.TasmanianSimpleSparseMatrix() np.testing.assert_almost_equal(np.empty([0,0], np.float64), pSparse.getDenseForm(), 14, "TasmanianSimpleSparseMatrix.getDense()", True) grid.makeLocalPolynomialGrid(2, 1, 4, 1, 'localp') aPoints = np.array([[0.33, 0.25], [-0.27, 0.39], [0.97, -0.76], [-0.44, 0.21], [-0.813, 0.03], [-0.666, 0.666]]) aDense = grid.evaluateHierarchicalFunctions(aPoints) pSparse = grid.evaluateSparseHierarchicalFunctions(aPoints) np.testing.assert_almost_equal(aDense, pSparse.getDenseForm(), 14, "evaluateSparseHierarchicalFunctions", True) grid.makeWaveletGrid(2, 1, 4, 1) aPoints = np.array([[0.33, 0.25], [-0.27, 0.39], [0.97, -0.76], [-0.44, 0.21], [-0.813, 0.03], [-0.666, 0.666]]) aDense = grid.evaluateHierarchicalFunctions(aPoints) pSparse = grid.evaluateSparseHierarchicalFunctions(aPoints) np.testing.assert_almost_equal(aDense, pSparse.getDenseForm(), 14, "evaluateSparseHierarchicalFunctions", True) def checkSetCoeffsMergeRefine(self): ''' Set the coefficients and use mergeRefinement() ''' aPoints = np.array([[0.33, 0.25], [-0.27, 0.39], [0.97, -0.76], [-0.44, 0.21], [-0.813, 0.03], [-0.666, 0.666]]) # set hierarchical coeffs/merge refinement gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() gridA.makeGlobalGrid(2, 1, 4, 'level', 'chebyshev') gridB.makeGlobalGrid(2, 1, 4, 'level', 'chebyshev') ttc.loadExpN2(gridA) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) gridA = TasmanianSG.TasmanianSparseGrid() gridB = TasmanianSG.TasmanianSparseGrid() gridA.makeGlobalGrid(2, 1, 4, 'level', 'fejer2') gridB.makeGlobalGrid(2, 1, 4, 'level', 'fejer2') ttc.loadExpN2(gridA) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) gridA.setAnisotropicRefinement('iptotal', 10, 0) gridB.setAnisotropicRefinement('iptotal', 10, 0) ttc.loadExpN2(gridA) gridB.mergeRefinement() self.assertEqual(gridA.getNumPoints(), gridB.getNumPoints(), 'different number of points after merge refinement') aRes = gridB.evaluateBatch(aPoints) np.testing.assert_almost_equal(aRes, np.zeros(aRes.shape), 14, "not zero after merged refinement", True) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) gridA.makeSequenceGrid(2, 1, 5, 'ipcurved', 'min-delta') gridB.makeSequenceGrid(2, 1, 5, 'ipcurved', 'min-delta') ttc.loadExpN2(gridA) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) gridA.setAnisotropicRefinement('iptotal', 30, 0) gridB.setAnisotropicRefinement('iptotal', 30, 0) ttc.loadExpN2(gridA) gridB.mergeRefinement() self.assertEqual(gridA.getNumPoints(), gridB.getNumPoints(), 'different number of points after merge refinement') aRes = gridB.evaluateBatch(aPoints) np.testing.assert_almost_equal(aRes, np.zeros(aRes.shape), 14, "not zero after merged refinement", True) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) gridA.makeLocalPolynomialGrid(2, 1, 4, 2, 'semi-localp') gridB.makeLocalPolynomialGrid(2, 1, 4, 2, 'semi-localp') ttc.loadExpN2(gridA) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) gridA.setSurplusRefinement(1.E-4, 0, 'classic') gridB.setSurplusRefinement(1.E-4, 0, 'classic') ttc.loadExpN2(gridA) gridB.mergeRefinement() self.assertEqual(gridA.getNumPoints(), gridB.getNumPoints(), 'different number of points after merge refinement') aRes = gridB.evaluateBatch(aPoints) np.testing.assert_almost_equal(aRes, np.zeros(aRes.shape), 14, "not zero after merged refinement", True) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) gridA.makeWaveletGrid(2, 1, 2, 1) gridB.makeWaveletGrid(2, 1, 2, 1) ttc.loadExpN2(gridA) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) gridA.setSurplusRefinement(1.E-3, 0, 'classic') gridB.setSurplusRefinement(1.E-3, 0, 'classic') ttc.loadExpN2(gridA) gridB.mergeRefinement() self.assertEqual(gridA.getNumPoints(), gridB.getNumPoints(), 'different number of points after merge refinement') aRes = gridB.evaluateBatch(aPoints) np.testing.assert_almost_equal(aRes, np.zeros(aRes.shape), 14, "not zero after merged refinement", True) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) gridA.makeFourierGrid(2, 1, 3, 'level') gridB.makeFourierGrid(2, 1, 3, 'level') ttc.loadExpN2(gridA) gridB.setHierarchicalCoefficients(gridA.getHierarchicalCoefficients()) ttc.compareGrids(gridA, gridB) def checkIntegrals(self): grid = TasmanianSG.TasmanianSparseGrid() lTests = ['grid.makeGlobalGrid(2, 1, 4, "level", "clenshaw-curtis")', 'grid.makeSequenceGrid(2, 1, 4, "level", "rleja")', 'grid.makeFourierGrid(2, 1, 3, "level")', 'grid.makeLocalPolynomialGrid(2, 1, 4)', 'grid.makeWaveletGrid(2, 1, 2)'] for t in lTests: exec(t) grid.setDomainTransform(np.array([[-3.0, 5.0], [-4.0, 2.0]])) ttc.loadExpN2(grid) aIntegrals = grid.integrateHierarchicalFunctions() aSurps = grid.getHierarchicalCoefficients() fResult = np.real(np.sum(aIntegrals * aSurps.reshape((aSurps.shape[0],)))) fExpected = grid.integrate() np.testing.assert_almost_equal(fResult, fExpected[0], 12, 'integrals different by too much') # check support grid.makeLocalPolynomialGrid(1, 1, 3) aSup = grid.getHierarchicalSupport() aResult = (1.0, 1.0, 1.0, 0.5, 0.5, 0.25, 0.25, 0.25, 0.25) np.testing.assert_almost_equal(aSup, np.array(aResult).reshape((9, 1)), 12, 'support different by too much') def checkValues(self): lTests = ['grid.makeGlobalGrid(2, 2, 3, "level", "clenshaw-curtis")', 'grid.makeSequenceGrid(2, 2, 3, "level", "rleja")', 'grid.makeFourierGrid(2, 2, 2, "level")', 'grid.makeLocalPolynomialGrid(2, 2, 2)', 'grid.makeWaveletGrid(2, 2, 2)'] for t in lTests: grid = TasmanianSG.TasmanianSparseGrid() aResult = grid.getLoadedValues() self.assertTrue(len(aResult) == 0, "failed to return a empty array") exec(t) iNP = grid.getNumNeeded() iOuts = 2 aReferece = np.array([float(i) for i in range(iNP * iOuts)]).reshape(iNP, iOuts) grid.loadNeededPoints(aReferece) aResult = grid.getLoadedValues() np.testing.assert_almost_equal(aResult, aReferece, 14, 'values in getLoadedValues() differ by too much') def performUnstructuredDataTests(self): self.checkAgainstKnown() self.checkSetCoeffsMergeRefine() self.checkIntegrals() self.checkValues() TASMANIAN-8.1/InterfaceSwig/000077500000000000000000000000001470551176200154375ustar00rootroot00000000000000TASMANIAN-8.1/InterfaceSwig/CMakeLists.txt000066400000000000000000000214721470551176200202050ustar00rootroot00000000000000if (Tasmanian_ENABLE_SWIG) find_package(SWIG COMPONENTS fortran REQUIRED) # SWIG is requested and available; make sure it's the Fortran fork. cmake_policy(SET CMP0078 "NEW") cmake_policy(SET CMP0086 "NEW") include(UseSWIG) endif() set(Tasmanian_GENERATE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated") # usage: Tasmanian_set_fortran_props(TARGET Tasmanian_libdream OUTPUT_NAME "tasmanianfortran") # sets the common properties of Tasmanian Fortran targets macro(Tasmanian_set_fortran_props) cmake_parse_arguments(Tasmanian_fprop "" "TARGET;OUTPUT_NAME" "" ${ARGN}) target_link_libraries(${Tasmanian_fprop_TARGET} Tasmanian_addons) set_target_properties(${Tasmanian_fprop_TARGET} PROPERTIES OUTPUT_NAME ${Tasmanian_fprop_OUTPUT_NAME} INSTALL_RPATH "${Tasmanian_rpath}" SOVERSION ${Tasmanian_VERSION_MAJOR} VERSION ${PROJECT_VERSION}) target_include_directories(${Tasmanian_fprop_TARGET} PUBLIC $) if (Tasmanian_ENABLE_MPI) # see the comments in the Addons/CMakeLists.txt target_link_libraries(${Tasmanian_fprop_TARGET} MPI::MPI_Fortran) endif() unset(Tasmanian_fprop_TARGET) unset(Tasmanian_fprop_OUTPUT_NAME) endmacro() function(tasmanian_add_swig_module tsg_name) # # Generates the wrappers using SWIG # # SWIG is available; actually generate the library dynamically. set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${tsg_name}.i") # We're using C++ set_property(SOURCE "${src_file}" PROPERTY CPLUSPLUS ON) # We need to include the source directory set_property(SOURCE "${src_file}" PROPERTY USE_TARGET_INCLUDE_DIRECTORIES ON) # Create the library (testing the generated wrappers) swig_add_library(${tsg_name} LANGUAGE Fortran TYPE USE_BUILD_SHARED_LIBS OUTPUT_DIR "${Tasmanian_GENERATE_DIR}" SOURCES "${src_file}" ${ARGN} ) Tasmanian_set_fortran_props(TARGET ${tsg_name} OUTPUT_NAME ${tsg_name}) endfunction() macro(Tasmanian_macro_add_libdfortran03) # # Build the Fortran module from an existing generated source file # - there is a hack here that adds a new methods inside the TasmanianSparseGrid class # - the generated files are read, then modified, then written to a "regenerated" folder # - only the updated files are compiled # - the original SWIG modules all have _swig in their names, the regenerated ones don't file(READ "${Tasmanian_GENERATE_DIR}/tasmanian_swig.f90" Tasmanian_generated_f90) string(REPLACE "module tasmanian_swig" "module tasmanian" Tasmanian_generated_f90 ${Tasmanian_generated_f90}) string(REPLACE " type, public :: TasmanianSparseGrid type(SwigClassWrapper), public :: swigdata contains" "type, public :: TasmanianSparseGrid type(SwigClassWrapper), public :: swigdata contains procedure :: returnPoints => tsgGetPoints procedure :: returnLoadedPoints => tsgGetLoadedPoints procedure :: returnNeededPoints => tsgGetNeededPoints procedure :: returnQuadratureWeights => tsgGetQuadratureWeights procedure :: returnHierarchicalCoefficients => tsgGetHierarchicalCoefficients procedure :: returnComplexHierarchicalCoefficients => tsgGetComplexHierarchicalCoefficients procedure :: setComplexHierarchicalCoefficients => tsgSetComplexHierarchicalCoefficients " Tasmanian_generated_f90 ${Tasmanian_generated_f90}) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/regenerated/tasmanian.f90" "${Tasmanian_generated_f90}") add_library(Tasmanian_libfortran03 "${CMAKE_CURRENT_BINARY_DIR}/regenerated/tasmanian.f90" "${Tasmanian_GENERATE_DIR}/tasmanian_swigFORTRAN_wrap.cxx") Tasmanian_set_fortran_props(TARGET Tasmanian_libfortran03 OUTPUT_NAME "tasmanianfortran") Tasmanian_rpath_target(TARGET Tasmanian_libfortran03) install(TARGETS Tasmanian_libfortran03 EXPORT "${Tasmanian_export_name}" RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib") if (Tasmanian_ENABLE_MPI) file(READ "${Tasmanian_GENERATE_DIR}/tasmanian_mpi_swig.f90" Tasmanian_generated_f90) string(REPLACE "module tasmanian_mpi_swig" "module tasmanian_mpi" Tasmanian_generated_f90 ${Tasmanian_generated_f90}) string(REPLACE "use tasmanian_swig" "use tasmanian" Tasmanian_generated_f90 ${Tasmanian_generated_f90}) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/regenerated/tasmanian_mpi.f90" "${Tasmanian_generated_f90}") add_library(Tasmanian_libfortranmpi03 "${CMAKE_CURRENT_BINARY_DIR}/regenerated/tasmanian_mpi.f90" "${Tasmanian_GENERATE_DIR}/tasmanian_mpi_swigFORTRAN_wrap.cxx") Tasmanian_set_fortran_props(TARGET Tasmanian_libfortranmpi03 OUTPUT_NAME "tasmanianfortranmpi") Tasmanian_rpath_target(TARGET Tasmanian_libfortranmpi03) target_link_libraries(Tasmanian_libfortranmpi03 Tasmanian_libfortran03) install(TARGETS Tasmanian_libfortranmpi03 EXPORT "${Tasmanian_export_name}" RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tasmanian_mpi.mod" DESTINATION include PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) endif() endmacro() ######################################################################## # Fortran librareis and command line tools ######################################################################## add_executable(Tasmanian_fortran_swig_tester ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/fortranswigtester.f90 ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/test_common.f90 ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/test_make_grid.f90 ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/test_domain.f90 ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/test_evaluate.f90 ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/test_update_grid.f90 ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/test_refinement.f90 ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/test_hierarchy.f90 ) set_target_properties(Tasmanian_fortran_swig_tester PROPERTIES OUTPUT_NAME "forswigtester") Tasmanian_set_fortran_linker(TARGET Tasmanian_fortran_swig_tester) if (Tasmanian_ENABLE_SWIG) # generate the interface tasmanian_add_swig_module(tasmanian_swig) if (Tasmanian_ENABLE_MPI) tasmanian_add_swig_module(tasmanian_mpi_swig) target_link_libraries(tasmanian_mpi_swig tasmanian_swig) endif() endif() Tasmanian_macro_add_libdfortran03() target_link_libraries(Tasmanian_fortran_swig_tester Tasmanian_libfortran03) add_test(Fortran2003 forswigtester) Tasmanian_set_test_properties(TESTS Fortran2003) Tasmanian_rpath_target(TARGET Tasmanian_fortran_swig_tester USE_CURRENT COMPONENTS SparseGrids DREAM) if (Tasmanian_ENABLE_MPI) add_executable(Tasmanian_fortran_mpiswig_tester ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/mpitester.f90 ${CMAKE_CURRENT_SOURCE_DIR}/FortranTests/test_common.f90 ) set_target_properties(Tasmanian_fortran_mpiswig_tester PROPERTIES OUTPUT_NAME "mpiforswigtester") Tasmanian_rpath_target(TARGET Tasmanian_fortran_mpiswig_tester USE_CURRENT COMPONENTS SparseGrids DREAM) Tasmanian_set_fortran_linker(TARGET Tasmanian_fortran_mpiswig_tester) target_link_libraries(Tasmanian_fortran_mpiswig_tester Tasmanian_libfortranmpi03) add_test(MPIFortran2003 ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/mpiforswigtester ${MPIEXEC_POSTFLAGS}) set_tests_properties(MPIFortran2003 PROPERTIES RUN_SERIAL ON) Tasmanian_set_test_properties(TESTS MPIFortran2003) endif() ######################################################################## # Installation ######################################################################## install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tasmanian.mod" DESTINATION include PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/FortranExamples/" DESTINATION "share/Tasmanian/examples/" FILES_MATCHING PATTERN "*.f90" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) TASMANIAN-8.1/InterfaceSwig/FortranExamples/000077500000000000000000000000001470551176200205515ustar00rootroot00000000000000TASMANIAN-8.1/InterfaceSwig/FortranExamples/example_sparse_grids.f90000066400000000000000000000055271470551176200253020ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== program TasmanianExamplesSGFortran implicit none call example_sparse_grid_01() call example_sparse_grid_02() call example_sparse_grid_03() call example_sparse_grid_04() end program TasmanianExamplesSGFortran TASMANIAN-8.1/InterfaceSwig/FortranExamples/example_sparse_grids_01.f90000066400000000000000000000041421470551176200255720ustar00rootroot00000000000000 subroutine example_sparse_grid_01() use Tasmanian use, intrinsic :: iso_c_binding type(TasmanianSparseGrid) :: grid integer :: dimension = 2, level = 6 integer :: i, num_points real(C_DOUBLE), dimension(:), allocatable :: weights real(C_DOUBLE), dimension(:,:), allocatable :: points double precision :: exact = 2.513723354063905D+0; double precision :: integral, err write(*,*) write(*,*) "-------------------------------------------------------------------------------------------------" write(*,*) "Example 1: integrate f(x,y) = exp(-x^2) * cos(y)" write(*,*) " using clenshaw-curtis nodes and grid of type level" grid = TasmanianSparseGrid() call grid%makeGlobalGrid(dimension, 0, level, tsg_type_level, tsg_rule_clenshawcurtis) num_points = grid%getNumPoints() allocate(weights(num_points)) call grid%getQuadratureWeights(weights) allocate(points(dimension, num_points)) call grid%getPoints(points(:,1)) integral = 0.0D-0 do i = 1, num_points integral = integral + weights(i) * exp( -points(1,i)**2 ) * cos( points(2,i) ) enddo err = abs(integral - exact) write(*,*) " at level: ", level write(*,*) " the grid has: ", num_points write(*,*) " integral: ", integral write(*,*) " error: ", err write(*,*) deallocate(weights, points) level = 7 call grid%makeGlobalGrid(dimension, 0, level, tsg_type_level, tsg_rule_clenshawcurtis) num_points = grid%getNumPoints() allocate(weights(num_points)) call grid%getQuadratureWeights(weights) allocate(points(dimension, num_points)) call grid%getPoints(points(:,1)) integral = 0.0D-0 do i = 1, num_points integral = integral + weights(i) * exp( -points(1,i)**2 ) * cos( points(2,i) ) enddo err = abs(integral - exact) write(*,*) " at level: ", level write(*,*) " the grid has: ", num_points write(*,*) " integral: ", integral write(*,*) " error: ", err write(*,*) deallocate(weights, points) call grid%release() end subroutine TASMANIAN-8.1/InterfaceSwig/FortranExamples/example_sparse_grids_02.f90000066400000000000000000000053671470551176200256050ustar00rootroot00000000000000 subroutine example_sparse_grid_02() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid integer :: dimension = 2, exactness = 20 integer :: i, num_points ! using the static array API requires only allocatable variables ! but the allocation has to be made before the call real(C_DOUBLE), dimension(:), allocatable :: weights real(C_DOUBLE), dimension(:,:), allocatable :: points ! pointer variables can be returned through the functional API ! allowing for more expressive calls real(C_DOUBLE), dimension(:), pointer :: pweights real(C_DOUBLE), dimension(:,:), pointer :: ppoints real(C_DOUBLE), dimension(2) :: lower, upper double precision :: exact = 1.861816427518323D+00; double precision :: integral, err write(*,*) "-------------------------------------------------------------------------------------------------" write(*,*) "Example 2: integrate f(x,y) = exp(-x^2) * cos(y) over [-5,5] x [-2,3]" write(*,*) " using Gauss-Patterson nodes and total degree polynomial space" grid = TasmanianGlobalGrid(dimension, 0, exactness, tsg_type_qptotal, tsg_rule_gausspatterson) num_points = grid%getNumPoints() lower = [ -5.0D-0, -2.0D-0 ] upper = [ 5.0D-0, 3.0D-0 ] call grid%setDomainTransform(lower, upper) allocate(weights(num_points)) call grid%getQuadratureWeights(weights) allocate(points(dimension, num_points)) call grid%getPoints(points(:,1)) integral = 0.0D-0 do i = 1, num_points integral = integral + weights(i) * exp( -points(1,i)**2 ) * cos( points(2,i) ) enddo err = abs(integral - exact) write(*,*) " at polynomial exactness: ", exactness write(*,*) " the grid has: ", num_points write(*,*) " integral: ", integral write(*,*) " error: ", err write(*,*) deallocate(weights, points) call grid%release() exactness = 40 grid = TasmanianGlobalGrid(dimension, 0, exactness, tsg_type_qptotal, tsg_rule_gausspatterson) num_points = grid%getNumPoints() call grid%setDomainTransform(lower, upper) ! using the functional API, saves the need to manually allocate the sizes pweights => tsgGetQuadratureWeights(grid) ppoints => tsgGetPoints(grid) integral = 0.0D-0 do i = 1, num_points integral = integral + pweights(i) * exp( -ppoints(1,i)**2 ) * cos( ppoints(2,i) ) enddo err = abs(integral - exact) write(*,*) " at polynomial exactness: ", exactness write(*,*) " the grid has: ", num_points write(*,*) " integral: ", integral write(*,*) " error: ", err write(*,*) deallocate(pweights, ppoints) call grid%release() end subroutine TASMANIAN-8.1/InterfaceSwig/FortranExamples/example_sparse_grids_03.f90000066400000000000000000000054541470551176200256030ustar00rootroot00000000000000subroutine example_sparse_grid_03() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid_cc, grid_gl, grid_gp integer :: prec real(C_DOUBLE) :: r real(C_DOUBLE), external :: ex3_get_error write(*,*) "-------------------------------------------------------------------------------------------------" write(*,*) "Example 3: integrate exp(-x1^2 - x2^2) * cos(x3) * cos(x4)" write(*,*) " for x1, x2 in [-5,5]; x3, x4 in [-2,3];" write(*,*) " using different rules and total degree polynomial space" write(*,*) write(*,*) " Clenshaw-Curtis Gauss-Legendre Gauss-Patterson" write(*,*) " precision points error points error points error" do prec = 5, 40, 5 grid_cc = TasmanianSparseGrid() grid_gl = TasmanianSparseGrid() grid_gp = TasmanianSparseGrid() call ex3_make_grid(grid_cc, prec, tsg_rule_clenshawcurtis) call ex3_make_grid(grid_gl, prec, tsg_rule_gausslegendreodd) call ex3_make_grid(grid_gp, prec, tsg_rule_gausspatterson) write(*,"(i10,i10,ES10.2,i10,ES10.2,i10,ES10.2)") prec, & grid_cc%getNumPoints(), ex3_get_error(grid_cc), & grid_gl%getNumPoints(), ex3_get_error(grid_gl), & grid_gp%getNumPoints(), ex3_get_error(grid_gp) call grid_cc%release() call grid_gl%release() call grid_gp%release() enddo write(*,*) write(*,*) "see the example comments in the on-line manual (or the equivalent C++ example)" write(*,*) end subroutine function ex3_get_error(grid) result(err) use Tasmanian use, intrinsic :: iso_c_binding implicit none real(C_DOUBLE) :: err type(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:), pointer :: weights real(C_DOUBLE), dimension(:,:), pointer :: points real(C_DOUBLE) :: integ integer :: i weights => tsgGetQuadratureWeights(grid) points => tsgGetPoints(grid) integ = 0.0D-0 do i = 1, grid%getNumPoints() integ = integ + weights(i) * exp(-points(1,i)**2 -points(2,i)**2) & * cos(points(3,i)) * cos(points(4,i)) enddo err = abs(1.861816427518323D+00 * 1.861816427518323D+00 - integ) deallocate(weights, points) end function subroutine ex3_make_grid(grid, prec, rule) use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid integer(C_INT), intent(in) :: prec, rule real(C_DOUBLE) :: lower(4), upper(4) grid = TasmanianGlobalGrid(4, 0, prec, tsg_type_qptotal, rule) lower = [ -5.0D-0, -5.0D-0, -2.0D-0, -2.0D-0 ] upper = [ 5.0D-0, 5.0D-0, 3.0D-0, 3.0D-0 ] call grid%setDomainTransform(lower, upper) end subroutine TASMANIAN-8.1/InterfaceSwig/FortranExamples/example_sparse_grids_04.f90000066400000000000000000000037011470551176200255750ustar00rootroot00000000000000subroutine example_sparse_grid_04() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: surrogate integer :: prec, i integer(C_INT), parameter :: num_inputs = 2 integer(C_INT), parameter :: num_outputs = 1 real(C_DOUBLE), dimension(:,:), allocatable :: points real(C_DOUBLE), dimension(:,:), allocatable :: values real(C_DOUBLE) :: x(2), y(1) write(*,*) "-------------------------------------------------------------------------------------------------" write(*,*) "Example 4: interpolate f(x,y) = exp(-x^2) * cos(y), using clenshaw-curtis iptotal rule" write(*,*) x = [ 0.3D-0, 0.7D-0 ] do prec = 6, 12, 6 surrogate = TasmanianGlobalGrid(num_inputs, num_outputs, prec, & tsg_type_iptotal, tsg_rule_clenshawcurtis) allocate(points(num_inputs, surrogate%getNumNeeded())) call surrogate%getNeededPoints(points(:,1)) allocate(values(num_outputs, surrogate%getNumNeeded())) do i = 1, surrogate%getNumNeeded() ! fill the values with the model values at the points values(1, i) = exp(-points(1,i)**2) * cos(points(2,i)) enddo call surrogate%loadNeededValues(values(:,1)) ! after the load call, the surrogate model is ready ! let y = surrogate(x) call surrogate%evaluate(x, y) write(*,"(A,i2)") " using polynomials of total degree up to: ", prec write(*,"(A,i3,A)") " the grid has: ", & surrogate%getNumPoints(), " points" write(*,"(A,ES11.4)") " interpolant at (0.3,0.7): ", y(1) write(*,"(A,ES11.4)") " error: ", & abs(y(1) - exp(-x(1)**2) * cos(x(2))) write(*,*) call surrogate%release() deallocate(points, values) enddo end subroutine TASMANIAN-8.1/InterfaceSwig/FortranTests/000077500000000000000000000000001470551176200200755ustar00rootroot00000000000000TASMANIAN-8.1/InterfaceSwig/FortranTests/fortranswigtester.f90000066400000000000000000000103201470551176200242050ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== program FORSWIGTESTER use Tasmanian implicit none type(TasmanianSparseGrid) :: grid integer :: i write(*,*) write(*,'(a,i1,a,i2)') 'Testing Tasmanian Fortran 2003-SWIG interface: version ', & grid%getVersionMajor(), ".", grid%getVersionMinor() write(*,*) write(*,'(a,a)') ' module version: ', grid%getVersion() write(*,'(a,a)') ' license: ', grid%getLicense() write(*,'(a,a)') ' git hash: ', grid%getGitCommitHash() write(*,'(a,a)') ' cxx flags: ', grid%getCmakeCxxFlags() write(*,'(a,l)') ' openmp enabled: ', grid%isOpenMPEnabled() write(*,'(a,l)') ' blas enabled: ', grid%isAccelerationAvailable(tsg_accel_cpu_blas) write(*,'(a,l)') ' magma enabled: ', grid%isAccelerationAvailable(tsg_accel_gpu_magma) write(*,'(a,l)') ' gpu enabled: ', grid%isAccelerationAvailable(tsg_accel_gpu_cuda) if (grid%isCudaEnabled()) then write(*,'(a,l)') ' gpu backend: CUDA' endif if (grid%isHipEnabled()) then write(*,'(a,l)') ' gpu backend: ROCm/HIP' endif if (grid%isDpcppEnabled()) then write(*,'(a,l)') ' gpu backend: OneAPI/DPC++' endif if (grid%isAccelerationAvailable(tsg_accel_gpu_cuda)) then do i = 1, grid%getNumGPUs() write(*,"(a,i1,a,a20,a,i6,a)") " device ", i-1, ": ", & grid%getGPUName(i-1), " with ", grid%getGPUMemory(i-1),"MB of RAM" enddo endif write(*,*) call test_make_grid() call test_domain_transforms() call test_eval_surrogate() call test_update_grids() call test_refinement() call test_hierarchy_transforms() write(*,*) end program FORSWIGTESTER TASMANIAN-8.1/InterfaceSwig/FortranTests/mpitester.f90000066400000000000000000000155241470551176200224400ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== program MPITESTER use Tasmanian use Tasmanian_mpi use mpi use, intrinsic :: iso_c_binding implicit none real(C_DOUBLE), dimension(:,:), pointer :: points, values integer :: mpi_ierr, me, i type(TasmanianSparseGrid) :: grid, scattered_grid, reference_grid ! ======= begin code ======= ! call MPI_Init(mpi_ierr) call MPI_Comm_rank(MPI_COMM_WORLD, me, mpi_ierr) if (ierr /= MPI_SUCCESS) then write(*,*) "ERROR: failed to initialize MPI" stop 1 endif reference_grid = TasmanianSequenceGrid(3, 1, 3, tsg_type_level, tsg_rule_rleja) grid = TasmanianSparseGrid() if (me == 0) then mpi_ierr = tsgMPIGridSend(reference_grid, 1, 11, MPI_COMM_WORLD) endif if (me == 1) then mpi_ierr = tsgMPIGridRecv(grid, 0, 11, MPI_COMM_WORLD) if (grid%getNumPoints() /= reference_grid%getNumPoints() .or. & grid%getNumDimensions() /= reference_grid%getNumDimensions()) then write(*,*) "ERROR: failed to receive the grid" stop 1 endif endif if (mpi_ierr /= MPI_SUCCESS) then write(*,*) "ERROR: failed at send/recv stage with mpi code: ", mpi_ierr error stop endif call grid%release() call MPI_Barrier(MPI_COMM_WORLD, mpi_ierr) if (me == 0) then write(*,*) "" write(*,*) " Tasmanian Fortran 2003 MPI Tests:" write(*,*) "" write(*,*) " MPI Send/Recv PASS" endif ! ! Testing tsgMPIGridBcast() ! ! make a silly grid to overwrite later grid = TasmanianSequenceGrid(2, 1, 0, tsg_type_level, tsg_rule_rleja) if (me == 2) then mpi_ierr = tsgMPIGridBcast(reference_grid, 2, MPI_COMM_WORLD) call grid%copyGrid(reference_grid) endif if (me /= 2) then mpi_ierr = tsgMPIGridBcast(grid, 2, MPI_COMM_WORLD) endif if (grid%getNumPoints() /= reference_grid%getNumPoints() .or. & grid%getNumDimensions() /= reference_grid%getNumDimensions()) then write(*,*) "ERROR: failed to broadcast the grid" error stop endif if (mpi_ierr /= MPI_SUCCESS) then write(*,*) "ERROR: failed at broadcast stage with mpi code: ", mpi_ierr error stop endif if (me == 0) then write(*,*) " MPI Bcast PASS" endif call MPI_Barrier(MPI_COMM_WORLD, mpi_ierr) ! Cleanup before scatter call grid%release() call reference_grid%release() ! scatter_grid is the destination, grid is the source scattered_grid = TasmanianSparseGrid() if (me == 1) then ! make the source grid grid = TasmanianLocalPolynomialGrid(3, 2, 4, 1, tsg_rule_localp) points => grid%returnPoints() allocate(values(2, grid%getNumPoints())) do i = 1, grid%getNumPoints() values(1, i) = exp(points(1,i) + points(2, i)) values(2, i) = exp(points(2,i) - points(3, i)) enddo call grid%loadNeededPoints(values(:, 1)) deallocate(points, values) else grid = TasmanianSparseGrid() ! non-null grid is needed outside of root endif reference_grid = TasmanianLocalPolynomialGrid(3, 1, 4, 1, tsg_rule_localp) if (me == 0) then ! rank 0 gets the first output points => reference_grid%returnPoints() allocate(values(1, reference_grid%getNumPoints())) do i = 1, reference_grid%getNumPoints() values(1, i) = exp(points(1,i) + points(2, i)) enddo call reference_grid%loadNeededPoints(values(:, 1)) deallocate(points, values) elseif (me == 1) then ! rank 1 gets the second output points => reference_grid%returnPoints() allocate(values(1, reference_grid%getNumPoints())) do i = 1, reference_grid%getNumPoints() values(1, i) = exp(points(2,i) - points(3, i)) enddo call reference_grid%loadNeededPoints(values(:, 1)) deallocate(points, values) endif ! rank 2 gets and empty grid mpi_ierr = tsgMPIGridScatterOutputs(grid, scattered_grid, 1, 47, MPI_COMM_WORLD) if (mpi_ierr /= 0) then write(*,*) "ERROR: calling tsgMPIGridScatterOutputs() with code: ", mpi_ierr error stop endif if (me == 2) then if (.not. scattered_grid%isEmpty()) then write(*,*) "rank 2 grid is not empty()" error stop endif else call approx_grid_pv(scattered_grid, reference_grid) endif ! clean up the grids call reference_grid%release() call scattered_grid%release() call grid%release() if (me == 0) then write(*,*) " MPI Scatter Outputs PASS" write(*,*) "" endif call MPI_Finalize(mpi_ierr) end program MPITESTER TASMANIAN-8.1/InterfaceSwig/FortranTests/test_common.f90000066400000000000000000000146041470551176200227510ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== ! Tests if two matrices with dimension n by m are approximately the same ! Calls "error stop" if the entries don't match to 1.D-12 subroutine approx2d(n, m, A, B) integer :: n, m integer :: i, j double precision, dimension(n,m) :: A, B do j = 1, m do i = 1, n if ( abs(A(i, j) - B(i, j)) > 1.D-12 ) then write(*,*) "mismatch: ", A(i, j), B(i, j) error stop endif enddo enddo end subroutine ! Same as approx2d() but uses a 1D array subroutine approx1d(n, x, y) integer :: n, i double precision, dimension(n) :: x, y do i = 1, n if ( abs(x(i) - y(i)) > 1.D-12 ) then write(*,*) x(i), y(i) error stop endif enddo end subroutine ! Same as approx2d() but works in single precision subroutine approx2df(n, m, A, B) integer :: n, m integer :: i, j real, dimension(n,m) :: A, B do j = 1, m do i = 1, n if ( abs(A(i, j) - B(i, j)) > 1.E-4 ) then write(*,*) "Error exceeds tolerance" error stop endif enddo enddo end subroutine ! similar to cassert, exits with "error stop" if the variable is false subroutine tassert(x) logical :: x if (.NOT. x) then error stop endif end subroutine ! compare grid points and weights subroutine approx_grid_pw(grid, grid_ref) use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid), intent(in) :: grid, grid_ref real(C_DOUBLE), dimension(:), pointer :: weights, weights_ref real(C_DOUBLE), dimension(:,:), pointer :: points, points_ref weights => grid%returnQuadratureWeights() points => grid%returnPoints() weights_ref => grid_ref%returnQuadratureWeights() points_ref => grid_ref%returnPoints() call approx1d(grid_ref%getNumPoints(), weights, weights_ref) call approx2d(grid_ref%getNumDimensions(), grid_ref%getNumPoints(), points, points_ref) deallocate(weights, weights_ref, points, points_ref) end subroutine ! compare grid points and values subroutine approx_grid_pv(grid, grid_ref) use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid), intent(in) :: grid, grid_ref real(C_DOUBLE), dimension(:,:), pointer :: vals, vals_ref real(C_DOUBLE), dimension(:,:), pointer :: points, points_ref integer :: nump nump = grid%getNumPoints() if (nump /= grid_ref%getNumPoints()) then write(*,*) "wrong number of points: ", nump, grid_ref%getNumPoints() error stop endif if (grid%getNumOutputs() /= grid_ref%getNumOutputs()) then write(*,*) "wrong number of points: ", nump, grid_ref%getNumPoints() error stop endif points => grid%returnPoints() points_ref => grid_ref%returnPoints() allocate(vals(grid%getNumOutputs(), nump)) allocate(vals_ref(grid%getNumOutputs(), nump)) call grid%evaluateBatch(points(:,1), nump, vals(:,1)) call grid_ref%evaluateBatch(points_ref(:,1), nump, vals_ref(:,1)) call approx2d(grid_ref%getNumDimensions(), grid_ref%getNumPoints(), points, points_ref) call approx2d(grid_ref%getNumOutputs(), nump, vals, vals_ref) deallocate(vals, vals_ref, points, points_ref) end subroutine ! print the points of the grid subroutine print_points(grid) use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid), intent(in) :: grid integer :: i, j real(C_DOUBLE), dimension(:,:), pointer :: points points => grid%returnPoints() do i = 1, grid%getNumPoints() do j = 1, grid%getNumDimensions() write(*, "(ES15.4)", advance="no") points(j, i) enddo write(*,*) enddo deallocate(points) end subroutine TASMANIAN-8.1/InterfaceSwig/FortranTests/test_domain.f90000066400000000000000000000175211470551176200227310ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== subroutine test_domain_range() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:), pointer :: weights real(C_DOUBLE), dimension(:,:), pointer :: points real(C_DOUBLE), dimension(3) :: lower, upper real(C_DOUBLE), dimension(3) :: tlower, tupper integer :: i lower = [3.0D-0, -7.0D-0, -12.0D-0] upper = [5.0D-0, -6.0D-0, 17.0D-0] grid = TasmanianGlobalGrid(3, 0, 2, tsg_type_level, tsg_rule_clenshawcurtis, [1, 1, 1]) call grid%setDomainTransform(lower, upper) call tassert(grid%isSetDomainTransfrom()) weights => grid%returnQuadratureWeights() points => grid%returnPoints() call tassert(abs(sum(weights) - 58.0D-0) < 1.D-11) do i = 1, 3 call tassert(abs(minval(points(i,:))-lower(i)) < 1.D-11) call tassert(abs(maxval(points(i,:))-upper(i)) < 1.D-11) enddo call grid%getDomainTransform(tlower, tupper) call approx1d(3, tlower, lower) call approx1d(3, tupper, upper) call grid%clearDomainTransform() call tassert(.not. grid%isSetDomainTransfrom()) deallocate(points, weights) call grid%release() end subroutine subroutine test_domain_gauss_hermite() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:), pointer :: weights double precision, parameter :: pi = 4.0D+0 * atan(1.0D+0) grid = TasmanianGlobalGrid(1, 0, 4, tsg_type_level, tsg_rule_gausshermite, alpha=2.0D+0) weights => grid%returnQuadratureWeights() call tassert(abs(sum(weights) - 0.5D+0 * sqrt(pi)) < 1.D-11) call tassert(grid%getAlpha() == 2.0D-0) call tassert(grid%getBeta() == 0.0D-0) deallocate(weights) call grid%release() end subroutine subroutine test_domain_gauss_jacobi() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:), pointer :: weights grid = TasmanianGlobalGrid(1, 0, 4, tsg_type_level, tsg_rule_gaussjacobi, beta=1.0D+0) weights => grid%returnQuadratureWeights() call tassert(abs(sum(weights) - 2.0D-0) < 1.D-11) call tassert(grid%getAlpha() == 0.0D-0) call tassert(grid%getBeta() == 1.0D-0) deallocate(weights) call grid%release() end subroutine subroutine test_domain_aniso() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:), pointer :: weights real(C_DOUBLE), dimension(:,:), pointer :: points real(C_DOUBLE) :: points_ref(2, 4) points_ref = reshape([ 0.0D+0, 0.0D+0, 0.0D+0, 1.0D+0, 0.0D+0, -1.0D+0, 1.0D+0, 0.0D+0 ], [2, 4]) grid = TasmanianGlobalGrid(2, 1, 2, tsg_type_level, tsg_rule_leja, [2, 1]) weights => grid%returnQuadratureWeights() points => grid%returnNeededPoints() call tassert(abs(sum(weights) - 4.0D-0) < 1.E-11) call approx2d(points, points_ref) deallocate(weights, points) call grid%release() end subroutine subroutine test_conformal_transform() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:), pointer :: weights real(C_DOUBLE), dimension(:,:), pointer :: points real(C_DOUBLE) :: err_normal, err_conformal integer :: i, l do l = 7,8 grid = TasmanianGlobalGrid(2, 0, l, tsg_type_qptotal, tsg_rule_gausspatterson) weights => grid%returnQuadratureWeights() points => grid%returnPoints() err_normal = 0.0d+0 do i = 1,grid%getNumPoints() err_normal = err_normal + weights(i) * ( 1.d0/((1.d0+5.d0*points(1,i)**2)*(1.d0+5.d0*points(2,i)**2 )) ) enddo err_normal = abs(err_normal-1.028825601981092d0**2) call grid%release() deallocate(weights, points) grid = TasmanianGlobalGrid(2, 0, l, tsg_type_qptotal, tsg_rule_gausspatterson) call grid%setConformalTransformASIN( (/4,4/) ) if (.not. grid%isSetConformalTransformASIN()) then write(*,*) "Conformal transform not set" error stop endif weights => grid%returnQuadratureWeights() points => grid%returnPoints() call grid%clearConformalTransform() if (grid%isSetConformalTransformASIN()) then write(*,*) "Conformal transform incorrectly set" error stop endif err_conformal = 0.0d+0 do i = 1,grid%getNumPoints() err_conformal = err_conformal + weights(i) * ( 1.d0/((1.d0+5.d0*points(1,i)**2)*(1.d0+5.d0*points(2,i)**2 )) ) enddo err_conformal = abs(err_conformal-1.028825601981092d0**2) call grid%release() deallocate(weights, points) if (err_normal < err_conformal) then write(*,*) "Conformal transform failed to improve convergence" error stop endif enddo end subroutine subroutine test_domain_transforms() call test_domain_range() call test_domain_gauss_hermite() call test_domain_gauss_jacobi() call test_domain_aniso() call test_conformal_transform() write(*,*) " Performing tests on domain transforms: PASS" end subroutine TASMANIAN-8.1/InterfaceSwig/FortranTests/test_evaluate.f90000066400000000000000000000210621470551176200232630ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== subroutine test_exact_eval_linear() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:,:), pointer :: points real(C_DOUBLE), dimension(:,:), pointer :: values real(C_DOUBLE) :: x(2, 3), y(2, 3), y_ref(2, 3) integer :: i, num_points grid = TasmanianSparseGrid() call grid%makeLocalPolynomialGrid(2, 2, 3) points => grid%returnNeededPoints() num_points = grid%getNumNeeded() allocate(values(2, num_points)) do i = 1, num_points ! constant and linear models are captures exactly by the linear grid values(1, i) = 3.0D-0 values(2, i) = 2.0D-0 + points(1, i) + 2.0D+0 * points(2, i) enddo call grid%loadNeededPoints(values(:, 1)) x = reshape([ 0.3D-0, 0.3D-0, 0.7D-0, -0.3D-0, 0.44D-0, -0.11D-0 ], [2, 3]) do i = 1, 3 y_ref(1, i) = 3.0D-0 y_ref(2, i) = 2.0D-0 + x(1, i) + 2.0D+0 * x(2, i) enddo call grid%evaluate(x(:,1), y(:,1)) call approx2d(2, 1, y, y_ref) y = 0.0D-0 call grid%evaluateFast(x(:,1), y(:,1)) call approx2d(2, 1, y, y_ref) y(1, 1) = 0.0D-0 y(2, 1) = 0.0D-0 call grid%evaluateBatch(x(:,1), 3, y(:,1)) call approx2d(2, 3, y, y_ref) deallocate(points, values) call grid%release() end subroutine subroutine test_exact_eval_cubic() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:,:), pointer :: points, lpoints real(C_DOUBLE), dimension(:,:), pointer :: values real(C_DOUBLE) :: x(2, 4), y(3, 4), y_ref(3, 4) integer :: i, num_points grid = TasmanianSparseGrid() call grid%makeLocalPolynomialGrid(2, 3, 3, 3) points => grid%returnNeededPoints() num_points = grid%getNumNeeded() allocate(values(3, num_points)) do i = 1, num_points ! constant and linear models are captures exactly by the linear grid values(1, i) = 3.0D-0 values(2, i) = points(1, i) + 2.0D+0 * points(2, i) values(3, i) = 5.0D-0 + points(1, i)**3 + 2.0D+0 * points(2, i)**2 enddo call grid%loadNeededValues(values(:, 1)) lpoints => grid%returnLoadedPoints() call approx2d(2, num_points, points, lpoints) x = reshape([ 0.3D-0, 0.3D-0, 0.7D-0, -0.3D-0, 0.44D-0, -0.11D-0, -0.17D-0, -0.83D-0 ], [2, 4]) do i = 1, 4 y_ref(1, i) = 3.0D-0 y_ref(2, i) = x(1, i) + 2.0D+0 * x(2, i) y_ref(3, i) = 5.0D-0 + x(1, i)**3 + 2.0D+0 * x(2, i)**2 enddo call grid%evaluate(x(:,1), y(:,1)) call approx2d(3, 1, y, y_ref) y(1:3, 1) = 0.0D-0 call grid%evaluateBatch(x(:,1), 4, y(:,1)) call approx2d(3, 4, y, y_ref) y(1:3, 1) = 0.0D-0 call grid%integrate(y(:,1)) call tassert(abs(y(1,1) - 12.0D-0) < 1.0D-11) deallocate(points, lpoints, values) call grid%release() end subroutine subroutine test_eval_sequence() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid, grid1, grid2 real(C_DOUBLE), dimension(:,:), pointer :: points real(C_DOUBLE), dimension(:,:), allocatable :: values real(C_DOUBLE) :: x(2, 4), y1(1, 4), y2(2, 4), y_ref1(1, 4), y_ref2(2, 4) real(C_FLOAT) :: xf(2, 4), yf(1, 4), y_ref1f(1, 4) integer :: i, num_points, default_gpu grid = TasmanianSparseGrid() grid1 = TasmanianSparseGrid() grid2 = TasmanianSparseGrid() if (grid%isDpcppEnabled()) then default_gpu = -1 else default_gpu = 0 endif call grid%makeSequenceGrid(2, 3, 6, tsg_type_level, tsg_rule_mindelta) points => grid%returnNeededPoints() num_points = grid%getNumNeeded() allocate(values(3, num_points)) do i = 1, num_points values(1, i) = 1.0D-0 + points(1, i) values(2, i) = 2.0D-0 * points(2, i) values(3, i) = points(1, i)**2 + points(2, i)**4 + points(1, i) * points(2, i) enddo call grid%loadNeededPoints(values(:,1)) call grid1%copyGrid(grid, 0, 1) call grid2%copyGrid(grid, 1) x = reshape([ 0.3D-0, 0.4D-0, 0.7D-0, -0.7D-0, 0.44D-0, -0.11D-0, -0.13D-0, -0.83D-0 ], [2, 4]) do i = 1, 4 y_ref1(1, i) = 1.0D-0 + x(1, i) y_ref2(1, i) = 2.0D-0 * x(2, i) y_ref2(2, i) = x(1, i)**2 + x(2, i)**4 + x(1, i) * x(2, i) y_ref1f(1, i) = y_ref1(1, i) enddo call grid1%evaluate(x(:,1), y1(:,1)) call approx2d(1, 1, y1, y_ref1) call grid1%enableAcceleration(tsg_accel_none) call grid1%evaluateBatch(x(:,1), 4, y1(:,1)) call approx2d(1, 4, y1, y_ref1) call grid2%enableAcceleration(tsg_accel_cpu_blas) call grid2%evaluateBatch(x(:,1), 4, y2(:,1)) call approx2d(2, 4, y2, y_ref2) if (grid2%isAccelerationAvailable(tsg_accel_cpu_blas)) then call tassert(grid2%getAccelerationType() == tsg_accel_cpu_blas) else call tassert(grid2%getAccelerationType() == tsg_accel_none) endif if (grid1%isAccelerationAvailable(tsg_accel_gpu_cuda)) then call grid1%enableAcceleration(tsg_accel_gpu_cuda) do i = 1, 4 xf(1,i) = x(1,i) xf(2,i) = x(2,i) enddo call grid1%evaluateBatch(xf(:,1), 4, yf(:,1)) call approx2df(1, 4, yf, y_ref1f) call grid1%enableAcceleration(tsg_accel_gpu_cuda, default_gpu) call grid%favorSparseAcceleration(.true.) ! has no effect ! reset yf to call eval fast in single precision yf(1, 1) = -333.33 call grid1%evaluateFast(xf(:,1), yf(:,1)) call approx2df(1, 1, yf, y_ref1f) call tassert(grid1%getGPUID() == default_gpu) call grid1%setGPUID(0) ! just for coverage endif deallocate(points, values) call grid%release() call grid1%release() call grid2%release() end subroutine subroutine test_eval_surrogate() call test_exact_eval_linear() call test_exact_eval_cubic() call test_eval_sequence() write(*,*) " Performing tests on evaluate methods: PASS" end subroutine TASMANIAN-8.1/InterfaceSwig/FortranTests/test_hierarchy.f90000066400000000000000000000203071470551176200234340ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== subroutine test_set_get_rcoeff() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: gridA, gridB real(C_DOUBLE), dimension(:,:), pointer :: points, vals, coeffs integer :: i, nump gridA = TasmanianSequenceGrid(2, 1, 11, tsg_type_level, tsg_rule_rleja) gridB = TasmanianSequenceGrid(2, 1, 11, tsg_type_level, tsg_rule_rleja) points => gridA%returnPoints() nump = gridA%getNumPoints() allocate(vals(1, nump)) do i = 1, nump vals(1,i) = exp(points(1,i)**2 - points(2,i)) enddo call gridA%loadNeededPoints(vals(:,1)) coeffs => gridA%returnHierarchicalCoefficients() call gridB%setHierarchicalCoefficients(coeffs(:,1)) call approx_grid_pv(gridA, gridB) deallocate(points, vals, coeffs) call gridA%release() call gridB%release() end subroutine subroutine test_set_get_ccoeff() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: gridA, gridB real(C_DOUBLE), dimension(:,:), pointer :: points, vals complex(C_DOUBLE_COMPLEX), dimension(:,:), pointer :: coeffs integer :: i, j, nump gridA = TasmanianFourierGrid(2, 2, 1, tsg_type_level) gridB = TasmanianFourierGrid(2, 2, 1, tsg_type_level) call tassert(gridA%isFourier()) points => gridA%returnPoints() nump = gridA%getNumPoints() allocate(vals(2, nump)) do i = 1, nump vals(1,i) = points(1,i) ** 3 - points(1,i) vals(2,i) = 0.25 * points(1,i) ** 4 - 0.5 * points(1,i) ** 2 enddo call gridA%loadNeededPoints(vals(:,1)) coeffs => gridA%returnComplexHierarchicalCoefficients() call gridB%setComplexHierarchicalCoefficients(coeffs) call approx_grid_pv(gridA, gridB) deallocate(points, vals, coeffs) call gridA%release() call gridB%release() end subroutine subroutine test_remove_by_coeff() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid, reduced real(C_DOUBLE), dimension(:,:), pointer :: points real(C_DOUBLE), dimension(:), pointer :: values grid = TasmanianLocalPolynomialGrid(2, 1, 1) points => grid%returnNeededPoints() allocate( values(grid%getNumNeeded()) ) values(:) = exp(-points(1,:)**2 - 0.5 *points(2,:)**2) call grid%loadNeededValues(values) reduced = TasmanianSparseGrid() call reduced%copyGrid(grid) call reduced%removePointsByHierarchicalCoefficient(0.6d0) deallocate( points ) points => reduced%returnLoadedPoints() call approx1d(6, points(:,1), (/0.d0, 0.d0, -1.d0, 0.d0, 1.d0, 0.d0/)) call reduced%copyGrid(grid) call reduced%removePointsByHierarchicalCoefficient(0.7d0, 0) call tassert( reduced%getNumLoaded() == 1 ) call reduced%copyGrid(grid) call reduced%removePointsByHierarchicalCoefficient(3) deallocate( points ) points => reduced%returnLoadedPoints() call approx1d(6, points(:,1), (/0.d0, 0.d0, -1.d0, 0.d0, 1.d0, 0.d0/)) call reduced%copyGrid(grid) call reduced%removePointsByHierarchicalCoefficient(1, 0) call tassert( reduced%getNumLoaded() == 1 ) call reduced%copyGrid(grid) call reduced%removePointsByHierarchicalCoefficient(3, 0, scale_correction=(/1.d0, 1.d0, 1.d0, 0.1d0, 0.1d0 /)) deallocate( points ) points => reduced%returnLoadedPoints() call approx1d(6, points(:,1), (/0.d0, 0.d0, 0.d0, -1.d0, 0.d0, 1.d0/)) call reduced%copyGrid(grid) call reduced%removePointsByHierarchicalCoefficient(0.3d0, 0, scale_correction=(/1.d0, 1.d0, 1.d0, 0.1d0, 0.1d0 /)) deallocate( points ) points => reduced%returnLoadedPoints() call approx1d(6, points(:,1), (/0.d0, 0.d0, 0.d0, -1.d0, 0.d0, 1.d0/)) deallocate( points, values ) call reduced%release() call grid%release() endsubroutine subroutine test_hierarchy_functions() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:,:), pointer :: points, lagr, ref_lagr real(C_DOUBLE), dimension(:), pointer :: integ integer :: i, j, n integer(C_INT), dimension(:), pointer :: pntr, indx real(C_DOUBLE), dimension(:), pointer :: vals grid = TasmanianGlobalGrid(2, 1, 1, tsg_type_level, tsg_rule_clenshawcurtis) points => grid%returnPoints() n = grid%getNumPoints() allocate( lagr(n, n), ref_lagr(n, n) ) do j = 1, n do i = 1, n lagr(i, j) = 5.d0 ref_lagr(i, j) = 0.d0 enddo enddo do i = 1, n ref_lagr(i, i) = 1.d0 enddo call grid%evaluateHierarchicalFunctions(points(:,1), n, lagr(:,1)) call approx2d(n, n, lagr, ref_lagr) call grid%makeLocalPolynomialGrid(1, 1, 1) allocate( integ(3) ) call grid%integrateHierarchicalFunctions(integ) call approx1d(3, integ, (/2.d0, 0.5d0, 0.5d0/)) ! doing the sparse test n = grid%evaluateSparseHierarchicalFunctionsGetNZ((/0.5d0/), 1) allocate( pntr(2), indx(n) ) allocate( vals(n) ) call grid%evaluateSparseHierarchicalFunctionsStatic((/0.5d0/), 1, pntr, indx, vals) call tassert(n == 2) call tassert(pntr(1) == 0 .and. pntr(2) == 2) call tassert(indx(1) == 0 .and. indx(2) == 2) call approx1d(2, vals, (/1.d0, 0.5d0/)) deallocate( pntr, indx ) deallocate( vals, integ, ref_lagr, lagr, points ) call grid%release() endsubroutine subroutine test_hierarchy_transforms() call test_set_get_rcoeff() call test_set_get_ccoeff() call test_remove_by_coeff() call test_hierarchy_functions() write(*,*) " Performing tests on hierarchy coefficients: PASS" end subroutine TASMANIAN-8.1/InterfaceSwig/FortranTests/test_make_grid.f90000066400000000000000000000405621470551176200234050ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== subroutine test_make_global_grid() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:,:), allocatable :: points, ref_points grid = TasmanianSparseGrid() call grid%makeGlobalGrid(2, 1, 1, tsg_type_level, tsg_rule_clenshawcurtis) allocate(points(grid%getNumDimensions(), grid%getNumPoints())) call grid%getPoints(points(:, 1)) ! correct set of points, the generated set above must match the ref_points ref_points = reshape([ 0.0D-0, 0.0D-0, 0.0D-0, -1.0D-0, 0.0D-0, 1.0D-0, -1.0D-0, 0.0D-0, 1.0D-0, 0.0D-0 ], [ 2, 5 ]) call approx2d(2, 5, points, ref_points) call tassert(grid%isGlobal()) call tassert(.NOT. grid%isLocalPolynomial()) call tassert(.NOT. grid%isEmpty()) call tassert(grid%getAlpha() .EQ. 0.0D-0) call tassert(grid%getBeta() .EQ. 0.0D-0) call tassert(grid%getOrder() .EQ. -1) deallocate(points) call grid%release() end subroutine subroutine test_make_global_grid_factory() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid integer(C_INT) :: aweights(2), level_limits(2) grid = TasmanianGlobalGrid(3, 0, 1, tsg_type_level, tsg_rule_fejer2) call tassert(grid%getNumPoints() == 7) call grid%release() aweights = [ 1, 2 ] grid = TasmanianGlobalGrid(2, 0, 1, tsg_type_level, tsg_rule_fejer2, aweights) call tassert(grid%getNumPoints() == 3) call grid%release() level_limits = [ 0, 1 ] grid = TasmanianGlobalGrid(2, 0, 1, tsg_type_level, tsg_rule_fejer2, aweights, level_limits=level_limits) call tassert(grid%getNumPoints() == 1) call grid%release() level_limits = [ 0, 3 ] grid = TasmanianGlobalGrid(2, 0, 7, tsg_type_level, tsg_rule_fejer2, level_limits=level_limits) call tassert(grid%getNumPoints() == 15) call grid%release() end subroutine subroutine test_make_global_grid_custom() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid, grid_ref integer(C_INT) :: level_limits(2) real(C_DOUBLE), dimension(:), pointer :: weights real(C_DOUBLE), dimension(:,:), pointer :: points character(len=:), allocatable :: description character(len=20) :: description_ref integer :: i, j, ferr open(unit=17, iostat=ferr, file='tasmanianFortranTestCustomRule.table',status='replace') call tassert(ferr == 0) write(17,*) "description: test Gauss-Legendre" write(17,*) "levels: 5" write(17,*) "1 1 2 3 3 5 4 7 5 9" do i = 0,4 grid = TasmanianGlobalGrid(1, 0, i, tsg_type_level, tsg_rule_gausslegendre) weights => grid%returnQuadratureWeights() points => grid%returnPoints() do j = 1, grid%getNumPoints() write(17,*) weights(j), points(1,j) enddo deallocate(points, weights) call grid%release() enddo close(unit=17) ! test custom rule grid = TasmanianGlobalGrid(2, 0, 4, tsg_type_level, tsg_rule_customtabulated, & custom_filename="tasmanianFortranTestCustomRule.table") grid_ref = TasmanianGlobalGrid(2, 0, 4, tsg_type_level, tsg_rule_gausslegendre) call approx_grid_pw(grid, grid_ref) call grid%release() call grid_ref%release() level_limits = [ 2, 2 ] grid = TasmanianGlobalGrid(2, 0, 4, tsg_type_level, tsg_rule_customtabulated, & custom_filename="tasmanianFortranTestCustomRule.table", & level_limits=level_limits) description_ref = "test Gauss-Legendre" description = grid%getCustomRuleDescription() call tassert(description .eq. description_ref) grid_ref = TasmanianGlobalGrid(2, 0, 4, tsg_type_level, tsg_rule_gausslegendre, level_limits=level_limits) call approx_grid_pw(grid, grid_ref) call grid%release() call grid_ref%release() end subroutine subroutine test_make_localp_grid() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:,:), allocatable :: points, ref_points grid = TasmanianSparseGrid() call grid%makeLocalPolynomialGrid(3, 0, 1, 3, tsg_rule_localp0) call tassert(grid%isLocalPolynomial()) call tassert(.not. grid%isSequence()) allocate(points(grid%getNumDimensions(), grid%getNumPoints())) call grid%getLoadedPoints(points(:, 1)) ! correct set of points, the generated set above must match the ref_points ref_points = reshape([ 0.0D-0, 0.0D-0, 0.0D-0, & 0.0D-0, 0.0D-0, -0.5D-0, & 0.0D-0, 0.0D-0, 0.5D-0, & 0.0D-0, -0.5D-0, 0.0D-0, & 0.0D-0, 0.5D-0, 0.0D-0, & -0.5D-0, 0.0D-0, 0.0D-0, & 0.5D-0, 0.0D-0, 0.0D-0 & ], [ 3, 7 ]) call approx2d(2, 7, points, ref_points) call tassert(grid%getOrder() .EQ. 3) deallocate(points) call grid%release() end subroutine subroutine test_make_localp_grid_factory() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid integer(C_INT) :: level_limits(3) grid = TasmanianLocalPolynomialGrid(3, 1, 1) call tassert(grid%getNumPoints() == 7) call tassert(grid%getOrder() == 1) call tassert(grid%getRule() == tsg_rule_localp) call grid%release() grid = TasmanianLocalPolynomialGrid(3, 1, 1, rule = tsg_rule_localp0) call tassert(grid%getNumPoints() == 7) call tassert(grid%getOrder() == 1) call tassert(grid%getRule() == tsg_rule_localp0) call grid%release() grid = TasmanianLocalPolynomialGrid(3, 1, 1, 2) call tassert(grid%getNumPoints() == 7) call tassert(grid%getOrder() == 2) call tassert(grid%getRule() == tsg_rule_localp) call grid%release() level_limits = [ 1, 1, 1 ] grid = TasmanianLocalPolynomialGrid(3, 1, 5, 3, rule = tsg_rule_localpb, level_limits=level_limits) call tassert(grid%getNumPoints() == 27) call tassert(grid%getOrder() == 3) call tassert(grid%getRule() == tsg_rule_localpb) call grid%release() end subroutine subroutine test_make_sequence_grid() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid, grid_read real(C_DOUBLE), dimension(:,:), allocatable :: points, ref_points grid = TasmanianSparseGrid() grid_read = TasmanianSparseGrid() call grid%makeSequenceGrid(1, 1, 3, tsg_type_iptotal, tsg_rule_leja) call grid%write("f03_test_file", .false.) call grid_read%read("f03_test_file") call tassert(grid_read%isSequence()) call tassert(.not. grid_read%isFourier()) ref_points = reshape([0.0D+0, 1.0D+0, -1.0D+0, sqrt(1.0D+0/3.0D+0)], [1, 4]) call tassert(grid_read%getNumPoints() .EQ. 4) allocate(points(grid%getNumDimensions(), grid%getNumPoints())) call grid_read%getNeededPoints(points(:, 1)) call approx2d(1, 4, points, ref_points) deallocate(points) call grid%release() call grid_read%release() end subroutine subroutine test_make_sequence_grid_factory() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid, grid_copy integer(C_INT) :: aweights(3), level_limits(3) aweights = [ 1, 3, 3 ] ! small level with strong weights, the grid is 1-D grid = TasmanianSequenceGrid(3, 0, 2, tsg_type_level, tsg_rule_leja, aweights) call tassert(grid%getNumPoints() == 3) ! 1-D grid at level 2 has 3 points call grid%release() level_limits = [ 1, 1, 1 ] ! large level with small limits makes the grid a tensor grid = TasmanianSequenceGrid(3, 0, 5, tsg_type_level, tsg_rule_leja, level_limits=level_limits) call tassert(grid%getNumPoints() == 8) ! 2^3 = 8, number of points for a tensor call grid%release() level_limits = [ 0, 1, 1 ] ! strong weights with heavy restriction, only 1 point is allowed grid = TasmanianSequenceGrid(3, 0, 2, tsg_type_level, tsg_rule_leja, aweights, level_limits) call tassert(grid%getNumPoints() == 1) call grid%release() grid = TasmanianSequenceGrid(2, 0, 1, tsg_type_qptotal, tsg_rule_minlebesgue) grid_copy = TasmanianSparseGrid(grid) call approx_grid_pw(grid_copy, grid) call grid%release() call grid_copy%release() end subroutine subroutine test_make_fourier_grid() use Tasmanian use, intrinsic :: iso_c_binding implicit none integer :: i type(TasmanianSparseGrid) :: grid, grid_copy real(C_DOUBLE), dimension(:), allocatable :: weights, ref_weights grid = TasmanianSparseGrid() grid_copy = TasmanianSparseGrid() call grid%makeFourierGrid(1, 1, 2, tsg_type_level) call grid_copy%copyGrid(grid) call tassert(grid_copy%isFourier()) call tassert(.not. grid_copy%isWavelet()) call tassert(grid_copy%getNumPoints() .EQ. 9) allocate(weights(grid_copy%getNumPoints())) allocate(ref_weights(grid_copy%getNumPoints())) call grid_copy%getQuadratureWeights(weights) do i = 1, 9 ref_weights(i) = 1.0D-0 / 9.0D-0 enddo call approx1d(9, weights, ref_weights) deallocate(weights, ref_weights) call grid%release() call grid_copy%release() end subroutine subroutine test_make_fourier_grid_factory() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid integer(C_INT) :: aweights(3), level_limits(3) aweights = [ 1, 3, 3 ] ! small level with strong weights, the grid is 1-D grid = TasmanianFourierGrid(3, 0, 2, tsg_type_level, aweights) call tassert(grid%getNumPoints() == 9) ! 1-D grid at level 2 has 9 points call grid%release() level_limits = [ 1, 1, 1 ] ! large level with small limits makes the grid a tensor grid = TasmanianFourierGrid(3, 0, 5, tsg_type_level, level_limits=level_limits) call tassert(grid%getNumPoints() == 27) ! 3^3 = 27, number of points for a tensor call grid%release() level_limits = [ 0, 1, 1 ] ! strong weights with heavy restriction, only 1 point is allowed grid = TasmanianFourierGrid(3, 0, 2, tsg_type_level, aweights, level_limits) call tassert(grid%getNumPoints() == 1) call grid%release() end subroutine subroutine test_make_wavelet_grid() use Tasmanian use, intrinsic :: iso_c_binding implicit none integer :: i type(TasmanianSparseGrid) :: grid real(C_DOUBLE) :: weights(3), ref_weights(3), x(1) grid = TasmanianSparseGrid() call tassert(grid%empty()) call grid%makeWaveletGrid(1, 1, 0) call tassert(.not. grid%empty()) call tassert(grid%isWavelet()) call tassert(.not. grid%isGlobal()) call tassert(grid%getNumPoints() .EQ. 3) call tassert(grid%getNumDimensions() .EQ. 1) call tassert(grid%getRule() .EQ. tsg_rule_wavelet) call tassert(.NOT. grid%isSetDomainTransfrom()) x = [-0.5] ref_weights = [0.5, 0.5, 0.0] call grid%getInterpolationWeights(x, weights) call approx1d(3, weights, ref_weights) call grid%release() end subroutine subroutine test_make_wavelet_grid_factory() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid integer(C_INT) :: level_limits(2) grid = TasmanianWaveletGrid(3, 1, 0) call tassert(grid%getNumPoints() == 27) call tassert(grid%getOrder() == 1) call tassert(grid%getRule() == tsg_rule_wavelet) call grid%release() grid = TasmanianWaveletGrid(2, 1, 0, order = 3) call tassert(grid%getNumPoints() == 25) call tassert(grid%getOrder() == 3) call tassert(grid%getRule() == tsg_rule_wavelet) call grid%release() level_limits = [ 1, 1 ] grid = TasmanianWaveletGrid(2, 1, 4, level_limits=level_limits) call tassert(grid%getNumPoints() == 25) call tassert(grid%getOrder() == 1) call grid%release() end subroutine subroutine test_read_copy_factory() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid, grid_duplicate grid = TasmanianSequenceGrid(2, 1, 1, tsg_type_iptotal, tsg_rule_maxlebesgue) call grid%write("f03_test_file") grid_duplicate = TasmanianReadGrid("f03_test_file") call approx_grid_pw(grid, grid_duplicate) call grid%release() call grid_duplicate%release() grid = TasmanianFourierGrid(2, 1, 2, tsg_type_hyperbolic) grid_duplicate = TasmanianCopyGrid(grid) call approx_grid_pw(grid, grid_duplicate) call grid%release() call grid_duplicate%release() grid = TasmanianSparseGrid() call grid%makeGlobalGrid(2, 3, 1, tsg_type_level, tsg_rule_gausslegendre, [2, 1]) grid_duplicate = TasmanianCopyGrid(grid, 0, 1) call approx_grid_pw(grid, grid_duplicate) call tassert(grid%getNumOutputs() == 3) call tassert(grid_duplicate%getNumOutputs() == 1) call grid%release() call grid_duplicate%release() grid = TasmanianSparseGrid() call grid%makeGlobalGrid(2, 4, 1, tsg_type_level, tsg_rule_gausslegendre, [2, 1], 0.0D-0) grid_duplicate = TasmanianCopyGrid(grid, 1) call approx_grid_pw(grid, grid_duplicate) call tassert(grid%getNumOutputs() == 4) call tassert(grid_duplicate%getNumOutputs() == 3) call grid%release() call grid_duplicate%release() end subroutine subroutine test_make_grid() call test_make_global_grid() call test_make_global_grid_factory() call test_make_global_grid_custom() call test_make_localp_grid() call test_make_localp_grid_factory() call test_make_sequence_grid() call test_make_sequence_grid_factory() call test_make_fourier_grid() call test_make_fourier_grid_factory() call test_make_wavelet_grid() call test_make_wavelet_grid_factory() call test_read_copy_factory() write(*,*) " Performing tests on make***Grid() methods: PASS" end subroutine TASMANIAN-8.1/InterfaceSwig/FortranTests/test_refinement.f90000066400000000000000000000213061470551176200236120ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== subroutine test_anisotropic_refinement() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:,:), pointer :: points real(C_DOUBLE), dimension(:), pointer :: values grid = TasmanianSequenceGrid(3, 1, 3, tsg_type_level, tsg_rule_leja, level_limits=(/3,2,1/)) points => grid%returnPoints() call approx2d(3, grid%getNumPoints(), points, & reshape( (/ 0.d0, 0.d0, 0.d0, & 0.d0, 0.d0, 1.d0, & 0.d0, 1.d0, 0.d0, & 0.d0, 1.d0, 1.d0, & 0.d0,-1.d0, 0.d0, & 0.d0,-1.d0, 1.d0, & 1.d0, 0.d0, 0.d0, & 1.d0, 0.d0, 1.d0, & 1.d0, 1.d0, 0.d0, & 1.d0, 1.d0, 1.d0, & 1.d0,-1.d0, 0.d0, & -1.d0, 0.d0, 0.d0, & -1.d0, 0.d0, 1.d0, & -1.d0, 1.d0, 0.d0, & 1.d0/sqrt(3.d0), 0.d0, 0.d0 /), & (/3, grid%getNumPoints()/) )) allocate( values(grid%getNumPoints()) ) values(:) = exp( -points(1,:)**2 - points(2,:)**2 ) call grid%loadNeededPoints(values) call grid%setAnisotropicRefinement(tsg_type_iptotal,5,0) if ( grid%getNumNeeded() .eq. 0 ) then write(*,*) "Failed to generate new points in refinement" error stop endif deallocate(points) points => grid%returnNeededPoints() call approx2d(3, grid%getNumNeeded(), points, & reshape( (/ 1.d0, -1.d0, 1.d0, & -1.d0, 1.d0, 1.d0, & -1.d0, -1.d0, 0.d0, & 1.d0/sqrt(3.d0), 0.d0, 1.d0, & 1.d0/sqrt(3.d0), 1.d0, 0.d0 /), & (/3, grid%getNumNeeded()/) )) call grid%clearRefinement() if ( .not. grid%getNumNeeded() .eq. 0 ) then write(*,*) "Failed to clear refinement" error stop endif call grid%setAnisotropicRefinement(tsg_type_iptotal, 1, 0, level_limits=(/2,2,1/)) deallocate(points) points => grid%returnNeededPoints() call approx2d(3, grid%getNumNeeded(), points, & reshape( (/ 1.d0, -1.d0, 1.d0, & -1.d0, 1.d0, 1.d0, & -1.d0, -1.d0, 0.d0 /), & (/3, grid%getNumNeeded()/) )) call grid%mergeRefinement() call tassert(grid%getNumLoaded() == 18) call tassert(grid%getNumNeeded() == 0) call grid%release() deallocate(points, values) end subroutine subroutine test_surplus_refinement() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid real(C_DOUBLE), dimension(:,:), pointer :: points real(C_DOUBLE), dimension(:), pointer :: values grid = TasmanianLocalPolynomialGrid(3, 1, 1, 1, tsg_rule_localp, level_limits=(/1,2,3/)) points => grid%returnPoints(); call approx2d(3, grid%getNumPoints(), points, & reshape( (/ 0.d0, 0.d0, 0.d0, & 0.d0, 0.d0,-1.d0, & 0.d0, 0.d0, 1.d0, & 0.d0,-1.d0, 0.d0, & 0.d0, 1.d0, 0.d0, & -1.d0, 0.d0, 0.d0, & 1.d0, 0.d0, 0.d0 /), & (/3, grid%getNumPoints()/) )) allocate( values(grid%getNumPoints()) ) values(:) = exp( -points(1,:)**2 - points(2,:)**2 ) call grid%loadNeededPoints(values) call grid%setSurplusRefinement(1.D-3, tsg_refine_classic) if ( grid%getNumNeeded() .eq. 0 ) then write(*,*) "Refinement failed to set new points" error stop endif deallocate(points) points => grid%returnNeededPoints() call approx2d(3, grid%getNumNeeded(), points, & reshape( (/ 0.d0, -1.d0, -1.d0, & 0.d0, -1.d0, 1.d0, & 0.d0, 1.d0, -1.d0, & 0.d0, 1.d0, 1.d0, & 0.d0, -5.d-1, 0.d0, & 0.d0, 5.d-1, 0.d0, & -1.d0, 0.d0, -1.d0, & -1.d0, 0.d0, 1.d0, & -1.d0, -1.d0, 0.d0, & -1.d0, 1.d0, 0.d0, & 1.d0, 0.d0, -1.d0, & 1.d0, 0.d0, 1.d0, & 1.d0, -1.d0, 0.d0, & 1.d0, 1.d0, 0.d0 /), & (/3, grid%getNumNeeded()/) )) call grid%clearLevelLimits() call grid%setSurplusRefinement(1.D-3, tsg_refine_classic, 0) call tassert(grid%getNumNeeded() == 16) call grid%setSurplusRefinement(1.D-3, tsg_refine_classic, -1, level_limits=(/3,2,0/)) deallocate(points) points => grid%returnNeededPoints() call approx2d(3, grid%getNumNeeded(), points, & reshape( (/ 0.d0, -5.d-1, 0.d0, & 0.d0, 5.d-1, 0.d0, & -1.d0, -1.d0, 0.d0, & -1.d0, 1.d0, 0.d0, & 1.d0, -1.d0, 0.d0, & 1.d0, 1.d0, 0.d0, & -5.d-1, 0.d0, 0.d0, & 5.d-1, 0.d0, 0.d0 /), & (/3, grid%getNumNeeded()/) )) call grid%setSurplusRefinement(1.D-3, tsg_refine_classic, -1, level_limits=(/3,2,0/), & scale_correction=(/0.d0, 0.d0, 0.d0, 1.d0, 0.d0, 0.d0, 0.d0/)) deallocate(points) points => grid%returnNeededPoints() call approx2d(3, grid%getNumNeeded(), points, & reshape( (/ 0.d0, -5.d-1, 0.d0, & -1.d0, -1.d0, 0.d0, & 1.d0, -1.d0, 0.d0 /), & (/3, grid%getNumNeeded()/) )) call grid%release() deallocate(points, values) end subroutine subroutine test_refinement() call test_anisotropic_refinement() call test_surplus_refinement() write(*,*) " Performing tests on refinement: PASS" end subroutine TASMANIAN-8.1/InterfaceSwig/FortranTests/test_update_grid.f90000066400000000000000000000147331470551176200237530ustar00rootroot00000000000000!================================================================================================================================================================================== ! Copyright (c) 2018, Miroslav Stoyanov ! ! This file is part of ! Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN ! ! Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: ! ! 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. ! ! 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions ! and the following disclaimer in the documentation and/or other materials provided with the distribution. ! ! 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse ! or promote products derived from this software without specific prior written permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ! IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, ! OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ! OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. ! THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, ! COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. ! THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, ! IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. !================================================================================================================================================================================== subroutine test_update_global() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid, grid_ref integer(C_INT) :: aweights(2), level_limits(2) aweights = [ 2, 1 ] level_limits = [ 2, 1 ] grid_ref = TasmanianGlobalGrid(2, 1, 3, tsg_type_level, tsg_rule_clenshawcurtis) grid = TasmanianGlobalGrid(2, 1, 1, tsg_type_level, tsg_rule_clenshawcurtis) call grid%updateGlobalGrid(3, tsg_type_level) call approx_grid_pw(grid, grid_ref) call grid_ref%release() call grid%release() grid_ref = TasmanianGlobalGrid(2, 1, 4, tsg_type_level, tsg_rule_fejer2, aweights) grid = TasmanianGlobalGrid(2, 1, 1, tsg_type_level, tsg_rule_fejer2) call grid%updateGlobalGrid(4, tsg_type_level, aweights) call approx_grid_pw(grid, grid_ref) call grid_ref%release() call grid%release() grid_ref = TasmanianGlobalGrid(2, 1, 6, tsg_type_level, tsg_rule_rleja, aweights, level_limits=level_limits) grid = TasmanianGlobalGrid(2, 1, 1, tsg_type_level, tsg_rule_rleja) call grid%updateGlobalGrid(6, tsg_type_level, aweights, level_limits) call approx_grid_pw(grid, grid_ref) call grid_ref%release() call grid%release() end subroutine subroutine test_update_sequence() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid, grid_ref integer(C_INT) :: aweights(4), level_limits(2) aweights = [ 2, 2, 1, 1 ] level_limits = [ 2, 1 ] grid_ref = TasmanianSequenceGrid(2, 1, 3, tsg_type_level, tsg_rule_minlebesgue) grid = TasmanianSequenceGrid(2, 1, 1, tsg_type_level, tsg_rule_minlebesgue) call grid%updateSequenceGrid(3, tsg_type_level) call approx_grid_pw(grid, grid_ref) call grid_ref%release() call grid%release() grid_ref = TasmanianSequenceGrid(2, 1, 4, tsg_type_level, tsg_rule_leja, aweights) grid = TasmanianSequenceGrid(2, 1, 1, tsg_type_level, tsg_rule_leja) call grid%updateSequenceGrid(4, tsg_type_level, aweights) call approx_grid_pw(grid, grid_ref) call grid_ref%release() call grid%release() grid_ref = TasmanianSequenceGrid(2, 1, 8, tsg_type_ipcurved, tsg_rule_rleja, aweights, level_limits=level_limits) grid = TasmanianSequenceGrid(2, 1, 1, tsg_type_ipcurved, tsg_rule_rleja) call grid%updateSequenceGrid(8, tsg_type_ipcurved, aweights, level_limits) call approx_grid_pw(grid, grid_ref) call grid_ref%release() call grid%release() end subroutine subroutine test_update_fourier() use Tasmanian use, intrinsic :: iso_c_binding implicit none type(TasmanianSparseGrid) :: grid, grid_ref integer(C_INT) :: aweights(2), level_limits(2) aweights = [ 2, 1 ] level_limits = [ 2, 1 ] grid_ref = TasmanianFourierGrid(2, 1, 2, tsg_type_iphyperbolic) grid = TasmanianFourierGrid(2, 1, 1, tsg_type_iphyperbolic) call grid%updateFourierGrid(2, tsg_type_iphyperbolic) call approx_grid_pw(grid, grid_ref) call grid_ref%release() call grid%release() grid_ref = TasmanianFourierGrid(2, 1, 4, tsg_type_level, aweights) grid = TasmanianFourierGrid(2, 1, 1, tsg_type_level) call grid%updateFourierGrid(4, tsg_type_level, aweights) call approx_grid_pw(grid, grid_ref) call grid_ref%release() call grid%release() grid_ref = TasmanianFourierGrid(2, 1, 8, tsg_type_iphyperbolic, aweights, level_limits=level_limits) grid = TasmanianFourierGrid(2, 1, 1, tsg_type_iphyperbolic) call grid%updateFourierGrid(8, tsg_type_iphyperbolic, aweights, level_limits) call approx_grid_pw(grid, grid_ref) call grid_ref%release() call grid%release() end subroutine subroutine test_update_grids() call test_update_global() call test_update_sequence() call test_update_fourier() write(*,*) " Performing tests on update grid methods: PASS" end subroutine TASMANIAN-8.1/InterfaceSwig/TasmanianSparseGrid.i000066400000000000000000000271111470551176200215120ustar00rootroot00000000000000/*! * \file TasmanianSparseGrid.i * * Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. * Distributed under a BSD 3-Clause License: see LICENSE for details. */ %{ #include "TasmanianSparseGrid.hpp" %} // Allow native fortran arrays to be passed to pointer/arrays %include %apply SWIGTYPE ARRAY[] { int*, float*, double*, int[], float[], double[] }; namespace TasGrid { // The array-like typemap can't be applied to return values %ignore TasmanianSparseGrid::getHierarchicalCoefficients; %ignore TasmanianSparseGrid::getLoadedValues; %ignore TasmanianSparseGrid::setSurplusRefinement(double, int); %ignore TasmanianSparseGrid::setSurplusRefinement(double, int, int const*); %ignore TasmanianSparseGrid::getPointsIndexes; %ignore TasmanianSparseGrid::getNeededIndexes; %ignore readGrid(std::string const&); %ignore TasmanianSparseGrid::operator=; %ignore TasmanianSparseGrid::operator EvaluateCallable; %ignore TasmanianSparseGrid::TasmanianSparseGrid(TasmanianSparseGrid &&); %ignore TasmanianSparseGrid::copyGrid(const TasmanianSparseGrid *, int, int); %ignore TasmanianSparseGrid::copyGrid(const TasmanianSparseGrid *, int); %ignore TasmanianSparseGrid::copyGrid(const TasmanianSparseGrid *); %ignore TasmanianSparseGrid::write(const std::string &, bool) const; %ignore TasmanianSparseGrid::write(std::string const&) const; %ignore TasmanianSparseGrid::read(const std::string &); %ignore TasmanianSparseGrid::beginConstruction; %ignore TasmanianSparseGrid::isUsingConstruction; %ignore TasmanianSparseGrid::loadConstructedPoints; %ignore TasmanianSparseGrid::finishConstruction; %ignore TasmanianSparseGrid::setCuBlasHandle; %ignore TasmanianSparseGrid::setCuSparseHandle; %ignore TasmanianSparseGrid::setCuSolverHandle; %ignore TasmanianSparseGrid::setRocBlasHandle; %ignore TasmanianSparseGrid::setRocSparseHandle; %ignore TasmanianSparseGrid::setSycleQueue; } // Using custom factory methods to take advantage of the Fortran optional parameters // Factory methods have many-many parameters, better optional ones helps a lot // makeEmpty() is equivalent to TasmanianSparseGrid(), can ignore %ignore TasGrid::makeGlobalGrid; %ignore TasGrid::makeSequenceGrid; %ignore TasGrid::makeFourierGrid; %ignore TasGrid::makeLocalPolynomialGrid; %ignore TasGrid::makeWaveletGrid; %ignore TasGrid::makeEmpty; %rename(TasmanianReadGrid) TasGrid::readGrid; %rename(TasmanianCopyGrid) TasGrid::copyGrid; // Additional functional-style of helper methods // Signature, makes them public for the module %insert("fdecl") %{ public :: TasmanianGlobalGrid public :: TasmanianSequenceGrid public :: TasmanianFourierGrid public :: TasmanianLocalPolynomialGrid public :: TasmanianWaveletGrid public :: tsgGetLoadedPoints public :: tsgGetNeededPoints public :: tsgGetPoints public :: tsgGetQuadratureWeights %} // implementation %insert("fsubprograms") %{ function TasmanianGlobalGrid(dims, outs, depth, gtype, rule, & aweights, alpha, beta, custom_filename, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT), intent(in) :: dims, outs, depth, gtype, rule integer(C_INT), optional, target :: aweights(:) double precision, optional :: alpha, beta character(len=*), target, optional :: custom_filename integer(C_INT), optional :: level_limits(dims) real(C_DOUBLE) :: al, be integer(C_INT), dimension(:), pointer :: aw(:) if ( present(aweights) ) then aw => aweights else allocate(aw(2 * dims)) aw(1:dims) = 1; aw(dims+1:2*dims) = 0; endif if ( present(alpha) ) then al = alpha else al = 0.0D-0 endif if ( present(beta) ) then be = beta else be = 0.0D-0 endif grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(custom_filename) ) then if ( present(level_limits) ) then call grid%makeGlobalGrid(dims, outs, depth, gtype, rule, aw, al, be, custom_filename, level_limits) else call grid%makeGlobalGrid(dims, outs, depth, gtype, rule, aw, al, be, custom_filename) endif else if ( present(level_limits) ) then call grid%makeGlobalGrid(dims, outs, depth, gtype, rule, aw, al, be, "", level_limits) else call grid%makeGlobalGrid(dims, outs, depth, gtype, rule, aw, al, be) endif endif if ( .not. present(aweights) ) then deallocate(aw) endif end function function TasmanianSequenceGrid(dims, outs, depth, gtype, rule, aweights, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT) :: dims, outs, depth, gtype, rule integer(C_INT), optional, target :: aweights(:) integer(C_INT), optional :: level_limits(dims) integer(C_INT) :: aw(2 * dims) grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(aweights) ) then if ( present(level_limits) ) then call grid%makeSequenceGrid(dims, outs, depth, gtype, rule, aweights, level_limits) else call grid%makeSequenceGrid(dims, outs, depth, gtype, rule, aweights) endif else if ( present(level_limits) ) then aw(1:dims) = 1; aw(dims+1:2*dims) = 0; call grid%makeSequenceGrid(dims, outs, depth, gtype, rule, aw, level_limits) else call grid%makeSequenceGrid(dims, outs, depth, gtype, rule) endif endif end function function TasmanianLocalPolynomialGrid(dims, outs, depth, order, rule, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT) :: dims, outs, depth, ord, ru integer(C_INT), optional :: order, rule integer(C_INT), optional :: level_limits(dims) if ( present(order) ) then ord = order else ord = 1 endif if ( present(rule) ) then ru = rule else ru = tsg_rule_localp endif grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(level_limits) ) then call grid%makeLocalPolynomialGrid(dims, outs, depth, ord, ru, level_limits) else call grid%makeLocalPolynomialGrid(dims, outs, depth, ord, ru) endif end function function TasmanianWaveletGrid(dims, outs, depth, order, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT) :: dims, outs, depth, ord integer(C_INT), optional :: order integer(C_INT), optional :: level_limits(dims) if ( present(order) ) then ord = order else ord = 1 endif grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(level_limits) ) then call grid%makeWaveletGrid(dims, outs, depth, ord, level_limits) else call grid%makeWaveletGrid(dims, outs, depth, ord) endif end function function TasmanianFourierGrid(dims, outs, depth, gtype, aweights, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT) :: dims, outs, depth, gtype integer(C_INT), dimension(:), optional :: aweights(:) integer(C_INT), optional :: level_limits(dims) integer(C_INT) :: aw(2 * dims) grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(aweights) ) then if ( present(level_limits) ) then call grid%makeFourierGrid(dims, outs, depth, gtype, aweights, level_limits) else call grid%makeFourierGrid(dims, outs, depth, gtype, aweights) endif else if ( present(level_limits) ) then aw(1:dims) = 1; aw(dims+1:2*dims) = 0; call grid%makeFourierGrid(dims, outs, depth, gtype, aw, level_limits) else call grid%makeFourierGrid(dims, outs, depth, gtype) endif endif end function function tsgGetLoadedPoints(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:,:), pointer :: fresult allocate(fresult(grid%getNumDimensions(), grid%getNumLoaded())) call grid%getLoadedPoints(fresult(:,1)) end function function tsgGetNeededPoints(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:,:), pointer :: fresult allocate(fresult(grid%getNumDimensions(), grid%getNumNeeded())) call grid%getNeededPoints(fresult(:,1)) end function function tsgGetPoints(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:,:), pointer :: fresult allocate(fresult(grid%getNumDimensions(), grid%getNumPoints())) call grid%getPoints(fresult(:,1)) end function function tsgGetQuadratureWeights(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:), pointer :: fresult allocate(fresult(grid%getNumPoints())) call grid%getQuadratureWeights(fresult) end function function tsgGetHierarchicalCoefficients(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:, :), pointer :: fresult if (grid%isFourier()) then allocate(fresult(grid%getNumOutputs(), 2 * grid%getNumLoaded())) else allocate(fresult(grid%getNumOutputs(), grid%getNumLoaded())) endif call grid%getHierarchicalCoefficientsStatic(fresult(:,1)) end function function tsgGetComplexHierarchicalCoefficients(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:, :), pointer :: real_coeff complex(C_DOUBLE_COMPLEX), dimension(:, :), pointer :: fresult integer :: i, j, numo, numl real_coeff => tsgGetHierarchicalCoefficients(grid) numl = grid%getNumLoaded() numo = grid%getNumOutputs() allocate(fresult(numo, numl)) do i = 1, numl do j = 1, numo fresult(j,i) = cmplx(real_coeff(j,i), real_coeff(j,i + numl), 8) enddo enddo deallocate(real_coeff) end function subroutine tsgSetComplexHierarchicalCoefficients(grid, coeffs) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(inout) :: grid complex(C_DOUBLE_COMPLEX), dimension(:, :) :: coeffs real(C_DOUBLE), dimension(:, :), pointer :: real_coeff integer :: i, j, numo, numl numl = grid%getNumPoints() numo = grid%getNumOutputs() allocate(real_coeff(numo, 2*numl)) do i = 1, numl do j = 1, numo real_coeff(j,i) = real(coeffs(j,i), 8) real_coeff(j,i + numl) = aimag(coeffs(j,i)) enddo enddo call grid%setHierarchicalCoefficients(real_coeff(:,1)) deallocate(real_coeff) end subroutine %} // Wrap clases/methods found in this file %include "TasmanianSparseGrid.hpp" namespace TasGrid { %rename(evaluateFast) TasmanianSparseGrid::evaluateFast; %template(evaluateFastDbl) TasmanianSparseGrid::evaluateFast; %rename(evaluateFast) TasmanianSparseGrid::evaluateFast; %template(evaluateFastFlt) TasmanianSparseGrid::evaluateFast; %rename(evaluateBatchGPU) TasmanianSparseGrid::evaluateBatchGPU; %template(evaluateBatchGPUDbl) TasmanianSparseGrid::evaluateBatchGPU; %rename(evaluateBatchGPU) TasmanianSparseGrid::evaluateBatchGPU; %template(evaluateBatchGPUFlt) TasmanianSparseGrid::evaluateBatchGPU; } %extend TasGrid::TasmanianSparseGrid{ void setConformalTransformASIN(int *truncation){ $self->setConformalTransformASIN( std::vector(truncation, truncation + $self->getNumDimensions()) ); } }; TASMANIAN-8.1/InterfaceSwig/generated/000077500000000000000000000000001470551176200173755ustar00rootroot00000000000000TASMANIAN-8.1/InterfaceSwig/generated/tasmanian_mpi_swig.f90000066400000000000000000000115371470551176200235750ustar00rootroot00000000000000! This file was automatically generated by SWIG (https://www.swig.org). ! Version 4.2.0 ! ! Do not make changes to this file unless you know what you are doing - modify ! the SWIG interface file instead. ! TASMANIAN project, https://github.com/ORNL/TASMANIAN ! Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. ! Distributed under an MIT open source license: see LICENSE for details. module tasmanian_mpi_swig use, intrinsic :: ISO_C_BINDING use tasmanian_swig implicit none private ! DECLARATION CONSTRUCTS integer, parameter :: swig_cmem_own_bit = 0 integer, parameter :: swig_cmem_rvalue_bit = 1 type, bind(C) :: SwigClassWrapper type(C_PTR), public :: cptr = C_NULL_PTR integer(C_INT), public :: cmemflags = 0 end type public :: tsgMPIGridSend public :: tsgMPIGridBcast public :: tsgMPIGridScatterOutputs interface tsgMPIGridRecv module procedure swigf_tsgMPIGridRecv__SWIG_1 end interface public :: tsgMPIGridRecv ! WRAPPER DECLARATIONS interface function swigc_tsgMPIGridSend(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_tsgMPIGridSend") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT) :: fresult end function function swigc_tsgMPIGridRecv__SWIG_1(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_tsgMPIGridRecv__SWIG_1") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT) :: fresult end function function swigc_tsgMPIGridBcast(farg1, farg2, farg3) & bind(C, name="_wrap_tsgMPIGridBcast") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT) :: fresult end function function swigc_tsgMPIGridScatterOutputs(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_tsgMPIGridScatterOutputs") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigClassWrapper), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT) :: fresult end function end interface contains ! MODULE SUBPROGRAMS function tsgMPIGridSend(grid, destination, tag, comm) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: grid integer(C_INT), intent(in) :: destination integer(C_INT), intent(in) :: tag integer :: comm integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 farg1 = grid%swigdata farg2 = destination farg3 = tag farg4 = int(comm, C_INT) fresult = swigc_tsgMPIGridSend(farg1, farg2, farg3, farg4) swig_result = fresult end function function swigf_tsgMPIGridRecv__SWIG_1(grid, source, tag, comm) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: grid integer(C_INT), intent(in) :: source integer(C_INT), intent(in) :: tag integer :: comm integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 farg1 = grid%swigdata farg2 = source farg3 = tag farg4 = int(comm, C_INT) fresult = swigc_tsgMPIGridRecv__SWIG_1(farg1, farg2, farg3, farg4) swig_result = fresult end function function tsgMPIGridBcast(grid, root, comm) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: grid integer(C_INT), intent(in) :: root integer :: comm integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 farg1 = grid%swigdata farg2 = root farg3 = int(comm, C_INT) fresult = swigc_tsgMPIGridBcast(farg1, farg2, farg3) swig_result = fresult end function function tsgMPIGridScatterOutputs(source, destination, root, tag, comm) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: source class(TasmanianSparseGrid), intent(in) :: destination integer(C_INT), intent(in) :: root integer(C_INT), intent(in) :: tag integer :: comm integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 type(SwigClassWrapper) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 farg1 = source%swigdata farg2 = destination%swigdata farg3 = root farg4 = tag farg5 = int(comm, C_INT) fresult = swigc_tsgMPIGridScatterOutputs(farg1, farg2, farg3, farg4, farg5) swig_result = fresult end function end module TASMANIAN-8.1/InterfaceSwig/generated/tasmanian_mpi_swigFORTRAN_wrap.cxx000066400000000000000000000303771470551176200260710ustar00rootroot00000000000000/* ---------------------------------------------------------------------------- * This file was automatically generated by SWIG (https://www.swig.org). * Version 4.2.0 * * Do not make changes to this file unless you know what you are doing - modify * the SWIG interface file instead. * ----------------------------------------------------------------------------- */ /* * TASMANIAN project, https://github.com/ORNL/TASMANIAN * Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. * Distributed under an MIT open source license: see LICENSE for details. */ /* ----------------------------------------------------------------------------- * This section contains generic SWIG labels for method/variable * declarations/attributes, and other compiler dependent labels. * ----------------------------------------------------------------------------- */ /* template workaround for compilers that cannot correctly implement the C++ standard */ #ifndef SWIGTEMPLATEDISAMBIGUATOR # if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) # define SWIGTEMPLATEDISAMBIGUATOR template # elif defined(__HP_aCC) /* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ /* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ # define SWIGTEMPLATEDISAMBIGUATOR template # else # define SWIGTEMPLATEDISAMBIGUATOR # endif #endif /* inline attribute */ #ifndef SWIGINLINE # if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) # define SWIGINLINE inline # else # define SWIGINLINE # endif #endif /* attribute recognised by some compilers to avoid 'unused' warnings */ #ifndef SWIGUNUSED # if defined(__GNUC__) # if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) # define SWIGUNUSED __attribute__ ((__unused__)) # else # define SWIGUNUSED # endif # elif defined(__ICC) # define SWIGUNUSED __attribute__ ((__unused__)) # else # define SWIGUNUSED # endif #endif #ifndef SWIG_MSC_UNSUPPRESS_4505 # if defined(_MSC_VER) # pragma warning(disable : 4505) /* unreferenced local function has been removed */ # endif #endif #ifndef SWIGUNUSEDPARM # ifdef __cplusplus # define SWIGUNUSEDPARM(p) # else # define SWIGUNUSEDPARM(p) p SWIGUNUSED # endif #endif /* internal SWIG method */ #ifndef SWIGINTERN # define SWIGINTERN static SWIGUNUSED #endif /* internal inline SWIG method */ #ifndef SWIGINTERNINLINE # define SWIGINTERNINLINE SWIGINTERN SWIGINLINE #endif /* exporting methods */ #if defined(__GNUC__) # if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) # ifndef GCC_HASCLASSVISIBILITY # define GCC_HASCLASSVISIBILITY # endif # endif #endif #ifndef SWIGEXPORT # if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) # if defined(STATIC_LINKED) # define SWIGEXPORT # else # define SWIGEXPORT __declspec(dllexport) # endif # else # if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) # define SWIGEXPORT __attribute__ ((visibility("default"))) # else # define SWIGEXPORT # endif # endif #endif /* calling conventions for Windows */ #ifndef SWIGSTDCALL # if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) # define SWIGSTDCALL __stdcall # else # define SWIGSTDCALL # endif #endif /* Deal with Microsoft's attempt at deprecating C standard runtime functions */ #if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) # define _CRT_SECURE_NO_DEPRECATE #endif /* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ #if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) # define _SCL_SECURE_NO_DEPRECATE #endif /* Deal with Apple's deprecated 'AssertMacros.h' from Carbon-framework */ #if defined(__APPLE__) && !defined(__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES) # define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 #endif /* Intel's compiler complains if a variable which was never initialised is * cast to void, which is a common idiom which we use to indicate that we * are aware a variable isn't used. So we just silence that warning. * See: https://github.com/swig/swig/issues/192 for more discussion. */ #ifdef __INTEL_COMPILER # pragma warning disable 592 #endif #if __cplusplus >=201103L # define SWIG_NULLPTR nullptr #else # define SWIG_NULLPTR NULL #endif /* C99 and C++11 should provide snprintf, but define SWIG_NO_SNPRINTF * if you're missing it. */ #if ((defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) || \ (defined __cplusplus && __cplusplus >= 201103L) || \ defined SWIG_HAVE_SNPRINTF) && \ !defined SWIG_NO_SNPRINTF # define SWIG_snprintf(O,S,F,A) snprintf(O,S,F,A) # define SWIG_snprintf2(O,S,F,A,B) snprintf(O,S,F,A,B) #else /* Fallback versions ignore the buffer size, but most of our uses either have a * fixed maximum possible size or dynamically allocate a buffer that's large * enough. */ # define SWIG_snprintf(O,S,F,A) sprintf(O,F,A) # define SWIG_snprintf2(O,S,F,A,B) sprintf(O,F,A,B) #endif #ifndef SWIGEXTERN # ifdef __cplusplus # define SWIGEXTERN extern # else # define SWIGEXTERN # endif #endif #define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ { throw std::logic_error("In " DECL ": " MSG); } #ifdef __cplusplus extern "C" { #endif SWIGEXPORT void SWIG_check_unhandled_exception_impl(const char* decl); SWIGEXPORT void SWIG_store_exception(const char* decl, int errcode, const char *msg); #ifdef __cplusplus } #endif #undef SWIG_exception_impl #define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ SWIG_store_exception(DECL, CODE, MSG); RETURNNULL; /* SWIG Errors applicable to all language modules, values are reserved from -1 to -99 */ #define SWIG_UnknownError -1 #define SWIG_IOError -2 #define SWIG_RuntimeError -3 #define SWIG_IndexError -4 #define SWIG_TypeError -5 #define SWIG_DivisionByZero -6 #define SWIG_OverflowError -7 #define SWIG_SyntaxError -8 #define SWIG_ValueError -9 #define SWIG_SystemError -10 #define SWIG_AttributeError -11 #define SWIG_MemoryError -12 #define SWIG_NullReferenceError -13 enum SwigMemFlags { SWIG_MEM_OWN = 0x01, SWIG_MEM_RVALUE = 0x02, }; #define SWIG_check_nonnull(PTR, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ if (!(PTR)) { \ SWIG_exception_impl(FUNCNAME, SWIG_NullReferenceError, \ "Cannot pass null " TYPENAME " (class " FNAME ") " \ "as a reference", RETURNNULL); \ } #define SWIG_VERSION 0x040200 #define SWIGFORTRAN #define SWIGPOLICY_TasGrid_TasmanianSparseGrid swig::ASSIGNMENT_DEFAULT #ifdef __cplusplus #include /* SwigValueWrapper is described in swig.swg */ template class SwigValueWrapper { struct SwigSmartPointer { T *ptr; SwigSmartPointer(T *p) : ptr(p) { } ~SwigSmartPointer() { delete ptr; } SwigSmartPointer& operator=(SwigSmartPointer& rhs) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = rhs.ptr; rhs.ptr = 0; return *this; } void reset(T *p) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = p; } } pointer; SwigValueWrapper& operator=(const SwigValueWrapper& rhs); SwigValueWrapper(const SwigValueWrapper& rhs); public: SwigValueWrapper() : pointer(0) { } SwigValueWrapper& operator=(const T& t) { SwigSmartPointer tmp(new T(t)); pointer = tmp; return *this; } #if __cplusplus >=201103L SwigValueWrapper& operator=(T&& t) { SwigSmartPointer tmp(new T(std::move(t))); pointer = tmp; return *this; } operator T&&() const { return std::move(*pointer.ptr); } #else operator T&() const { return *pointer.ptr; } #endif T *operator&() const { return pointer.ptr; } static void reset(SwigValueWrapper& t, T *p) { t.pointer.reset(p); } }; /* * SwigValueInit() is a generic initialisation solution as the following approach: * * T c_result = T(); * * doesn't compile for all types for example: * * unsigned int c_result = unsigned int(); */ template T SwigValueInit() { return T(); } #if __cplusplus >=201103L # define SWIG_STD_MOVE(OBJ) std::move(OBJ) #else # define SWIG_STD_MOVE(OBJ) OBJ #endif #endif #include /* Support for the `contract` feature. * * Note that RETURNNULL is first because it's inserted via a 'Replaceall' in * the fortran.cxx file. */ #define SWIG_contract_assert(RETURNNULL, EXPR, MSG) \ if (!(EXPR)) { SWIG_exception_impl("$decl", SWIG_ValueError, MSG, RETURNNULL); } #define SWIG_as_voidptr(a) const_cast< void * >(static_cast< const void * >(a)) #define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),reinterpret_cast< void** >(a)) #include #include #include #include struct SwigClassWrapper { void* cptr; int cmemflags; }; SWIGINTERN SwigClassWrapper SwigClassWrapper_uninitialized() { SwigClassWrapper result; result.cptr = NULL; result.cmemflags = 0; return result; } extern "C" { SWIGEXPORT int _wrap_tsgMPIGridSend(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = 0 ; int arg2 ; int arg3 ; MPI_Comm arg4 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const &", "TasmanianSparseGrid", "TasGrid::MPIGridSend< true >(TasGrid::TasmanianSparseGrid const &,int,int,MPI_Comm)", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = MPI_Comm_f2c((MPI_Fint)*farg4); result = (int)TasGrid::SWIGTEMPLATEDISAMBIGUATOR MPIGridSend< true >((TasGrid::TasmanianSparseGrid const &)*arg1,arg2,arg3,SWIG_STD_MOVE(arg4)); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_tsgMPIGridRecv__SWIG_1(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = 0 ; int arg2 ; int arg3 ; MPI_Comm arg4 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid &", "TasmanianSparseGrid", "TasGrid::MPIGridRecv< true >(TasGrid::TasmanianSparseGrid &,int,int,MPI_Comm)", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = MPI_Comm_f2c((MPI_Fint)*farg4); result = (int)TasGrid::SWIGTEMPLATEDISAMBIGUATOR MPIGridRecv< true >(*arg1,arg2,arg3,SWIG_STD_MOVE(arg4)); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_tsgMPIGridBcast(SwigClassWrapper *farg1, int const *farg2, int const *farg3) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = 0 ; int arg2 ; MPI_Comm arg3 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid &", "TasmanianSparseGrid", "TasGrid::MPIGridBcast< true >(TasGrid::TasmanianSparseGrid &,int,MPI_Comm)", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = MPI_Comm_f2c((MPI_Fint)*farg3); result = (int)TasGrid::SWIGTEMPLATEDISAMBIGUATOR MPIGridBcast< true >(*arg1,arg2,SWIG_STD_MOVE(arg3)); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_tsgMPIGridScatterOutputs(SwigClassWrapper *farg1, SwigClassWrapper *farg2, int const *farg3, int const *farg4, int const *farg5) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = 0 ; TasGrid::TasmanianSparseGrid *arg2 = 0 ; int arg3 ; int arg4 ; MPI_Comm arg5 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const &", "TasmanianSparseGrid", "TasGrid::MPIGridScatterOutputs< true >(TasGrid::TasmanianSparseGrid const &,TasGrid::TasmanianSparseGrid &,int,int,MPI_Comm)", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; SWIG_check_nonnull(farg2->cptr, "TasGrid::TasmanianSparseGrid &", "TasmanianSparseGrid", "TasGrid::MPIGridScatterOutputs< true >(TasGrid::TasmanianSparseGrid const &,TasGrid::TasmanianSparseGrid &,int,int,MPI_Comm)", return 0); arg2 = (TasGrid::TasmanianSparseGrid *)farg2->cptr; arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = MPI_Comm_f2c((MPI_Fint)*farg5); result = (int)TasGrid::SWIGTEMPLATEDISAMBIGUATOR MPIGridScatterOutputs< true >((TasGrid::TasmanianSparseGrid const &)*arg1,*arg2,arg3,arg4,SWIG_STD_MOVE(arg5)); fresult = (int)(result); return fresult; } } // extern TASMANIAN-8.1/InterfaceSwig/generated/tasmanian_swig.f90000066400000000000000000004221421470551176200227260ustar00rootroot00000000000000! This file was automatically generated by SWIG (https://www.swig.org). ! Version 4.2.0 ! ! Do not make changes to this file unless you know what you are doing - modify ! the SWIG interface file instead. ! TASMANIAN project, https://github.com/ORNL/TASMANIAN ! Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. ! Distributed under an MIT open source license: see LICENSE for details. module tasmanian_swig use, intrinsic :: ISO_C_BINDING implicit none private ! DECLARATION CONSTRUCTS integer(C_INT), public, & bind(C, name="tasmanian_ierr") :: ierr type, bind(C) :: SwigArrayWrapper type(C_PTR), public :: data = C_NULL_PTR integer(C_SIZE_T), public :: size = 0 end type public :: get_serr integer(C_INT), parameter, public :: SWIG_UnknownError = -1_C_INT integer(C_INT), parameter, public :: SWIG_IOError = -2_C_INT integer(C_INT), parameter, public :: SWIG_RuntimeError = -3_C_INT integer(C_INT), parameter, public :: SWIG_IndexError = -4_C_INT integer(C_INT), parameter, public :: SWIG_TypeError = -5_C_INT integer(C_INT), parameter, public :: SWIG_DivisionByZero = -6_C_INT integer(C_INT), parameter, public :: SWIG_OverflowError = -7_C_INT integer(C_INT), parameter, public :: SWIG_SyntaxError = -8_C_INT integer(C_INT), parameter, public :: SWIG_ValueError = -9_C_INT integer(C_INT), parameter, public :: SWIG_SystemError = -10_C_INT integer(C_INT), parameter, public :: SWIG_AttributeError = -11_C_INT integer(C_INT), parameter, public :: SWIG_MemoryError = -12_C_INT integer(C_INT), parameter, public :: SWIG_NullReferenceError = -13_C_INT ! enum TasGrid::TypeIndexRelation enum, bind(c) enumerator :: tsg_type_abeforeb enumerator :: tsg_type_bbeforea enumerator :: tsg_type_asameb end enum integer, parameter, public :: tsg_TypeIndexRelation = kind(tsg_type_abeforeb) public :: tsg_type_abeforeb, tsg_type_bbeforea, tsg_type_asameb ! enum TasGrid::TypeDepth enum, bind(c) enumerator :: tsg_type_none enumerator :: tsg_type_level enumerator :: tsg_type_curved enumerator :: tsg_type_hyperbolic enumerator :: tsg_type_iptotal enumerator :: tsg_type_qptotal enumerator :: tsg_type_ipcurved enumerator :: tsg_type_qpcurved enumerator :: tsg_type_iphyperbolic enumerator :: tsg_type_qphyperbolic enumerator :: tsg_type_tensor enumerator :: tsg_type_iptensor enumerator :: tsg_type_qptensor end enum integer, parameter, public :: tsg_TypeDepth = kind(tsg_type_none) public :: tsg_type_none, tsg_type_level, tsg_type_curved, tsg_type_hyperbolic, tsg_type_iptotal, tsg_type_qptotal, & tsg_type_ipcurved, tsg_type_qpcurved, tsg_type_iphyperbolic, tsg_type_qphyperbolic, tsg_type_tensor, tsg_type_iptensor, & tsg_type_qptensor ! enum TasGrid::TypeOneDRule enum, bind(c) enumerator :: tsg_rule_none enumerator :: tsg_rule_clenshawcurtis enumerator :: tsg_rule_clenshawcurtis0 enumerator :: tsg_rule_fejer2 enumerator :: tsg_rule_chebyshev enumerator :: tsg_rule_chebyshevodd enumerator :: tsg_rule_leja enumerator :: tsg_rule_lejaodd enumerator :: tsg_rule_rleja enumerator :: tsg_rule_rlejadouble2 enumerator :: tsg_rule_rlejadouble4 enumerator :: tsg_rule_rlejaodd enumerator :: tsg_rule_rlejashifted enumerator :: tsg_rule_rlejashiftedeven enumerator :: tsg_rule_rlejashifteddouble enumerator :: tsg_rule_maxlebesgue enumerator :: tsg_rule_maxlebesgueodd enumerator :: tsg_rule_minlebesgue enumerator :: tsg_rule_minlebesgueodd enumerator :: tsg_rule_mindelta enumerator :: tsg_rule_mindeltaodd enumerator :: tsg_rule_gausslegendre enumerator :: tsg_rule_gausslegendreodd enumerator :: tsg_rule_gausspatterson enumerator :: tsg_rule_gausschebyshev1 enumerator :: tsg_rule_gausschebyshev1odd enumerator :: tsg_rule_gausschebyshev2 enumerator :: tsg_rule_gausschebyshev2odd enumerator :: tsg_rule_gaussgegenbauer enumerator :: tsg_rule_gaussgegenbauerodd enumerator :: tsg_rule_gaussjacobi enumerator :: tsg_rule_gaussjacobiodd enumerator :: tsg_rule_gausslaguerre enumerator :: tsg_rule_gausslaguerreodd enumerator :: tsg_rule_gausshermite enumerator :: tsg_rule_gausshermiteodd enumerator :: tsg_rule_customtabulated enumerator :: tsg_rule_localp enumerator :: tsg_rule_localp0 enumerator :: tsg_rule_semilocalp enumerator :: tsg_rule_localpb enumerator :: tsg_rule_wavelet enumerator :: tsg_rule_fourier end enum integer, parameter, public :: tsg_TypeOneDRule = kind(tsg_rule_none) public :: tsg_rule_none, tsg_rule_clenshawcurtis, tsg_rule_clenshawcurtis0, tsg_rule_fejer2, tsg_rule_chebyshev, & tsg_rule_chebyshevodd, tsg_rule_leja, tsg_rule_lejaodd, tsg_rule_rleja, tsg_rule_rlejadouble2, tsg_rule_rlejadouble4, & tsg_rule_rlejaodd, tsg_rule_rlejashifted, tsg_rule_rlejashiftedeven, tsg_rule_rlejashifteddouble, tsg_rule_maxlebesgue, & tsg_rule_maxlebesgueodd, tsg_rule_minlebesgue, tsg_rule_minlebesgueodd, tsg_rule_mindelta, tsg_rule_mindeltaodd, & tsg_rule_gausslegendre, tsg_rule_gausslegendreodd, tsg_rule_gausspatterson, tsg_rule_gausschebyshev1, & tsg_rule_gausschebyshev1odd, tsg_rule_gausschebyshev2, tsg_rule_gausschebyshev2odd, tsg_rule_gaussgegenbauer, & tsg_rule_gaussgegenbauerodd, tsg_rule_gaussjacobi, tsg_rule_gaussjacobiodd, tsg_rule_gausslaguerre, & tsg_rule_gausslaguerreodd, tsg_rule_gausshermite, tsg_rule_gausshermiteodd, tsg_rule_customtabulated, tsg_rule_localp, & tsg_rule_localp0, tsg_rule_semilocalp, tsg_rule_localpb, tsg_rule_wavelet, tsg_rule_fourier ! enum TasGrid::TypeRefinement enum, bind(c) enumerator :: tsg_refine_classic enumerator :: tsg_refine_parents_first enumerator :: tsg_refine_direction_selective enumerator :: tsg_refine_fds enumerator :: tsg_refine_stable enumerator :: tsg_refine_none end enum integer, parameter, public :: tsg_TypeRefinement = kind(tsg_refine_classic) public :: tsg_refine_classic, tsg_refine_parents_first, tsg_refine_direction_selective, tsg_refine_fds, tsg_refine_stable, & tsg_refine_none ! enum TasGrid::TypeAcceleration enum, bind(c) enumerator :: tsg_accel_none enumerator :: tsg_accel_cpu_blas enumerator :: tsg_accel_gpu_default enumerator :: tsg_accel_gpu_cublas enumerator :: tsg_accel_gpu_cuda enumerator :: tsg_accel_gpu_magma end enum integer, parameter, public :: tsg_TypeAcceleration = kind(tsg_accel_none) public :: tsg_accel_none, tsg_accel_cpu_blas, tsg_accel_gpu_default, tsg_accel_gpu_cublas, tsg_accel_gpu_cuda, & tsg_accel_gpu_magma public :: TasmanianGlobalGrid public :: TasmanianSequenceGrid public :: TasmanianFourierGrid public :: TasmanianLocalPolynomialGrid public :: TasmanianWaveletGrid public :: tsgGetLoadedPoints public :: tsgGetNeededPoints public :: tsgGetPoints public :: tsgGetQuadratureWeights integer, parameter :: swig_cmem_own_bit = 0 integer, parameter :: swig_cmem_rvalue_bit = 1 type, bind(C) :: SwigClassWrapper type(C_PTR), public :: cptr = C_NULL_PTR integer(C_INT), public :: cmemflags = 0 end type ! class TasGrid::TasmanianSparseGrid type, public :: TasmanianSparseGrid type(SwigClassWrapper), public :: swigdata contains procedure :: release => swigf_TasmanianSparseGrid_release procedure, nopass :: getVersion => swigf_TasmanianSparseGrid_getVersion procedure, nopass :: getVersionMajor => swigf_TasmanianSparseGrid_getVersionMajor procedure, nopass :: getVersionMinor => swigf_TasmanianSparseGrid_getVersionMinor procedure, nopass :: getLicense => swigf_TasmanianSparseGrid_getLicense procedure, nopass :: getGitCommitHash => swigf_TasmanianSparseGrid_getGitCommitHash procedure, nopass :: getCmakeCxxFlags => swigf_TasmanianSparseGrid_getCmakeCxxFlags procedure, nopass :: isOpenMPEnabled => swigf_TasmanianSparseGrid_isOpenMPEnabled procedure, nopass :: isCudaEnabled => swigf_TasmanianSparseGrid_isCudaEnabled procedure, nopass :: isHipEnabled => swigf_TasmanianSparseGrid_isHipEnabled procedure, nopass :: isDpcppEnabled => swigf_TasmanianSparseGrid_isDpcppEnabled procedure, private :: swigf_TasmanianSparseGrid_write__SWIG_0 procedure, private :: swigf_TasmanianSparseGrid_write__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_read__SWIG_0 procedure, private :: swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_5 procedure, private :: swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_6 procedure, private :: swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_7 procedure, private :: swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_8 procedure, private :: swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_9 procedure, private :: swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_10 procedure, private :: swigf_TasmanianSparseGrid_makeSequenceGrid__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_makeSequenceGrid__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_makeSequenceGrid__SWIG_4 procedure, private :: swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_4 procedure, private :: swigf_TasmanianSparseGrid_makeWaveletGrid__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_makeWaveletGrid__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_makeWaveletGrid__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_makeFourierGrid__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_makeFourierGrid__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_makeFourierGrid__SWIG_4 procedure, private :: swigf_TasmanianSparseGrid_copyGrid__SWIG_0 procedure, private :: swigf_TasmanianSparseGrid_copyGrid__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_copyGrid__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_updateGlobalGrid__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_updateGlobalGrid__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_updateGlobalGrid__SWIG_4 procedure, private :: swigf_TasmanianSparseGrid_updateSequenceGrid__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_updateSequenceGrid__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_updateSequenceGrid__SWIG_4 procedure, private :: swigf_TasmanianSparseGrid_updateFourierGrid__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_updateFourierGrid__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_updateFourierGrid__SWIG_4 procedure, private :: swigf_TasmanianSparseGrid_updateGrid__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_updateGrid__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_updateGrid__SWIG_4 procedure :: getAlpha => swigf_TasmanianSparseGrid_getAlpha procedure :: getBeta => swigf_TasmanianSparseGrid_getBeta procedure :: getOrder => swigf_TasmanianSparseGrid_getOrder procedure :: getNumDimensions => swigf_TasmanianSparseGrid_getNumDimensions procedure :: getNumOutputs => swigf_TasmanianSparseGrid_getNumOutputs procedure :: getRule => swigf_TasmanianSparseGrid_getRule procedure :: getCustomRuleDescription => swigf_TasmanianSparseGrid_getCustomRuleDescription procedure :: getNumLoaded => swigf_TasmanianSparseGrid_getNumLoaded procedure :: getNumNeeded => swigf_TasmanianSparseGrid_getNumNeeded procedure :: getNumPoints => swigf_TasmanianSparseGrid_getNumPoints procedure, private :: swigf_TasmanianSparseGrid_getLoadedPoints__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_getNeededPoints__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_getPoints__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_getQuadratureWeights__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_getInterpolationWeights__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_getDifferentiationWeights__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_loadNeededValues__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_loadNeededPoints__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_evaluate__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_evaluateBatch__SWIG_0 procedure, private :: swigf_TasmanianSparseGrid_evaluateBatch__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_integrate__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_differentiate__SWIG_2 procedure :: isGlobal => swigf_TasmanianSparseGrid_isGlobal procedure :: isSequence => swigf_TasmanianSparseGrid_isSequence procedure :: isLocalPolynomial => swigf_TasmanianSparseGrid_isLocalPolynomial procedure :: isWavelet => swigf_TasmanianSparseGrid_isWavelet procedure :: isFourier => swigf_TasmanianSparseGrid_isFourier procedure :: isEmpty => swigf_TasmanianSparseGrid_isEmpty procedure :: empty => swigf_TasmanianSparseGrid_empty procedure, private :: swigf_TasmanianSparseGrid_setDomainTransform__SWIG_1 procedure :: isSetDomainTransfrom => swigf_TasmanianSparseGrid_isSetDomainTransfrom procedure :: clearDomainTransform => swigf_TasmanianSparseGrid_clearDomainTransform procedure, private :: swigf_TasmanianSparseGrid_getDomainTransform__SWIG_1 procedure :: isSetConformalTransformASIN => swigf_TasmanianSparseGrid_isSetConformalTransformASIN procedure :: clearConformalTransform => swigf_TasmanianSparseGrid_clearConformalTransform procedure :: clearLevelLimits => swigf_TasmanianSparseGrid_clearLevelLimits procedure, private :: swigf_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_4 procedure, private :: swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_5 procedure, private :: swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_6 procedure :: clearRefinement => swigf_TasmanianSparseGrid_clearRefinement procedure :: mergeRefinement => swigf_TasmanianSparseGrid_mergeRefinement procedure :: getHierarchicalCoefficientsStatic => swigf_TasmanianSparseGrid_getHierarchicalCoefficientsStatic procedure, private :: swigf_TasmanianSparseGrid_setHierarchicalCoefficients__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_evaluateHierarchicalFunctions__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_integrateHierarchicalFu1JSVB3__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_printStats__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_enableAcceleration__SWIG_0 procedure, private :: swigf_TasmanianSparseGrid_enableAcceleration__SWIG_1 procedure :: favorSparseAcceleration => swigf_TasmanianSparseGrid_favorSparseAcceleration procedure :: getAccelerationType => swigf_TasmanianSparseGrid_getAccelerationType procedure, nopass :: isAccelerationAvailable => swigf_TasmanianSparseGrid_isAccelerationAvailable procedure :: setGPUID => swigf_TasmanianSparseGrid_setGPUID procedure :: getGPUID => swigf_TasmanianSparseGrid_getGPUID procedure, nopass :: getNumGPUs => swigf_TasmanianSparseGrid_getNumGPUs procedure, nopass :: getGPUMemory => swigf_TasmanianSparseGrid_getGPUMemory procedure, nopass :: getGPUName => swigf_TasmanianSparseGrid_getGPUName procedure, private :: swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_0 procedure, private :: swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_3 procedure, private :: swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_4 procedure, private :: swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_5 procedure :: evaluateSparseHierarchicalFunctionsGetNZ => swigf_TasmanianSparseGrid_evaluateSparseHierarchicalFunct1CQM1I procedure :: evaluateSparseHierarchicalFunctionsStatic => swigf_TasmanianSparseGrid_evaluateSparseHierarchicalFunct1HRJEE procedure, private :: swigf_TasmanianSparseGrid_evaluateFast__SWIG_0 procedure, private :: swigf_TasmanianSparseGrid_evaluateFast__SWIG_2 procedure, private :: swigf_TasmanianSparseGrid_evaluateBatchGPU__SWIG_0 procedure, private :: swigf_TasmanianSparseGrid_evaluateBatchGPU__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_setConformalTransformASIN__SWIG_1 procedure, private :: swigf_TasmanianSparseGrid_op_assign__ generic :: getDomainTransform => swigf_TasmanianSparseGrid_getDomainTransform__SWIG_1 generic :: setConformalTransformASIN => swigf_TasmanianSparseGrid_setConformalTransformASIN__SWIG_1 generic :: assignment(=) => swigf_TasmanianSparseGrid_op_assign__ generic :: setHierarchicalCoefficients => swigf_TasmanianSparseGrid_setHierarchicalCoefficients__SWIG_1 generic :: integrate => swigf_TasmanianSparseGrid_integrate__SWIG_1 generic :: differentiate => swigf_TasmanianSparseGrid_differentiate__SWIG_2 generic :: setSurplusRefinement => swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_3, & swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_4, swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_5, & swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_6 generic :: setAnisotropicRefinement => swigf_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_1, & swigf_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_2 generic :: updateGrid => swigf_TasmanianSparseGrid_updateGrid__SWIG_2, swigf_TasmanianSparseGrid_updateGrid__SWIG_3, & swigf_TasmanianSparseGrid_updateGrid__SWIG_4 generic :: integrateHierarchicalFunctions => swigf_TasmanianSparseGrid_integrateHierarchicalFu1JSVB3__SWIG_2 generic :: getQuadratureWeights => swigf_TasmanianSparseGrid_getQuadratureWeights__SWIG_2 generic :: makeGlobalGrid => swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_5, & swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_6, swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_7, & swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_8, swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_9, & swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_10 generic :: copyGrid => swigf_TasmanianSparseGrid_copyGrid__SWIG_0, swigf_TasmanianSparseGrid_copyGrid__SWIG_1, & swigf_TasmanianSparseGrid_copyGrid__SWIG_2 generic :: removePointsByHierarchicalCoefficient => swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_0, & swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_1, & swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_2, & swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_3, & swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_4, & swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_5 generic :: loadNeededValues => swigf_TasmanianSparseGrid_loadNeededValues__SWIG_1 generic :: getLoadedPoints => swigf_TasmanianSparseGrid_getLoadedPoints__SWIG_2 generic :: getPoints => swigf_TasmanianSparseGrid_getPoints__SWIG_2 generic :: enableAcceleration => swigf_TasmanianSparseGrid_enableAcceleration__SWIG_0, & swigf_TasmanianSparseGrid_enableAcceleration__SWIG_1 generic :: makeLocalPolynomialGrid => swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_1, & swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_2, swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_3, & swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_4 generic :: printStats => swigf_TasmanianSparseGrid_printStats__SWIG_1 generic :: evaluate => swigf_TasmanianSparseGrid_evaluate__SWIG_1 generic :: updateSequenceGrid => swigf_TasmanianSparseGrid_updateSequenceGrid__SWIG_2, & swigf_TasmanianSparseGrid_updateSequenceGrid__SWIG_3, swigf_TasmanianSparseGrid_updateSequenceGrid__SWIG_4 generic :: evaluateBatchGPU => swigf_TasmanianSparseGrid_evaluateBatchGPU__SWIG_0, & swigf_TasmanianSparseGrid_evaluateBatchGPU__SWIG_1 generic :: getNeededPoints => swigf_TasmanianSparseGrid_getNeededPoints__SWIG_2 generic :: makeSequenceGrid => swigf_TasmanianSparseGrid_makeSequenceGrid__SWIG_2, & swigf_TasmanianSparseGrid_makeSequenceGrid__SWIG_3, swigf_TasmanianSparseGrid_makeSequenceGrid__SWIG_4 generic :: evaluateFast => swigf_TasmanianSparseGrid_evaluateFast__SWIG_0, swigf_TasmanianSparseGrid_evaluateFast__SWIG_2 generic :: setDomainTransform => swigf_TasmanianSparseGrid_setDomainTransform__SWIG_1 generic :: updateFourierGrid => swigf_TasmanianSparseGrid_updateFourierGrid__SWIG_2, & swigf_TasmanianSparseGrid_updateFourierGrid__SWIG_3, swigf_TasmanianSparseGrid_updateFourierGrid__SWIG_4 generic :: read => swigf_TasmanianSparseGrid_read__SWIG_0 generic :: write => swigf_TasmanianSparseGrid_write__SWIG_0, swigf_TasmanianSparseGrid_write__SWIG_1 generic :: loadNeededPoints => swigf_TasmanianSparseGrid_loadNeededPoints__SWIG_1 generic :: makeFourierGrid => swigf_TasmanianSparseGrid_makeFourierGrid__SWIG_2, & swigf_TasmanianSparseGrid_makeFourierGrid__SWIG_3, swigf_TasmanianSparseGrid_makeFourierGrid__SWIG_4 generic :: getInterpolationWeights => swigf_TasmanianSparseGrid_getInterpolationWeights__SWIG_3 generic :: getDifferentiationWeights => swigf_TasmanianSparseGrid_getDifferentiationWeights__SWIG_3 generic :: evaluateBatch => swigf_TasmanianSparseGrid_evaluateBatch__SWIG_0, swigf_TasmanianSparseGrid_evaluateBatch__SWIG_1 generic :: updateGlobalGrid => swigf_TasmanianSparseGrid_updateGlobalGrid__SWIG_2, & swigf_TasmanianSparseGrid_updateGlobalGrid__SWIG_3, swigf_TasmanianSparseGrid_updateGlobalGrid__SWIG_4 generic :: makeWaveletGrid => swigf_TasmanianSparseGrid_makeWaveletGrid__SWIG_1, & swigf_TasmanianSparseGrid_makeWaveletGrid__SWIG_2, swigf_TasmanianSparseGrid_makeWaveletGrid__SWIG_3 generic :: evaluateHierarchicalFunctions => swigf_TasmanianSparseGrid_evaluateHierarchicalFunctions__SWIG_2 end type TasmanianSparseGrid public :: TasmanianReadGrid interface TasmanianSparseGrid module procedure swigf_new_TasmanianSparseGrid__SWIG_0, swigf_new_TasmanianSparseGrid__SWIG_1 end interface interface TasmanianCopyGrid module procedure swigf_TasmanianCopyGrid__SWIG_0, swigf_TasmanianCopyGrid__SWIG_1, swigf_TasmanianCopyGrid__SWIG_2 end interface public :: TasmanianCopyGrid ! WRAPPER DECLARATIONS interface subroutine SWIG_free(cptr) & bind(C, name="free") use, intrinsic :: ISO_C_BINDING type(C_PTR), value :: cptr end subroutine function swigc_get_serr() & bind(C, name="_wrap_get_serr") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper type(SwigArrayWrapper) :: fresult end function function swigc_new_TasmanianSparseGrid__SWIG_0() & bind(C, name="_wrap_new_TasmanianSparseGrid__SWIG_0") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper) :: fresult end function function swigc_new_TasmanianSparseGrid__SWIG_1(farg1) & bind(C, name="_wrap_new_TasmanianSparseGrid__SWIG_1") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigClassWrapper) :: fresult end function subroutine swigc_delete_TasmanianSparseGrid(farg1) & bind(C, name="_wrap_delete_TasmanianSparseGrid") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(inout) :: farg1 end subroutine function swigc_TasmanianSparseGrid_getVersion() & bind(C, name="_wrap_TasmanianSparseGrid_getVersion") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper type(SwigArrayWrapper) :: fresult end function function swigc_TasmanianSparseGrid_getVersionMajor() & bind(C, name="_wrap_TasmanianSparseGrid_getVersionMajor") & result(fresult) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getVersionMinor() & bind(C, name="_wrap_TasmanianSparseGrid_getVersionMinor") & result(fresult) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getLicense() & bind(C, name="_wrap_TasmanianSparseGrid_getLicense") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper type(SwigArrayWrapper) :: fresult end function function swigc_TasmanianSparseGrid_getGitCommitHash() & bind(C, name="_wrap_TasmanianSparseGrid_getGitCommitHash") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper type(SwigArrayWrapper) :: fresult end function function swigc_TasmanianSparseGrid_getCmakeCxxFlags() & bind(C, name="_wrap_TasmanianSparseGrid_getCmakeCxxFlags") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper type(SwigArrayWrapper) :: fresult end function function swigc_TasmanianSparseGrid_isOpenMPEnabled() & bind(C, name="_wrap_TasmanianSparseGrid_isOpenMPEnabled") & result(fresult) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_isCudaEnabled() & bind(C, name="_wrap_TasmanianSparseGrid_isCudaEnabled") & result(fresult) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_isHipEnabled() & bind(C, name="_wrap_TasmanianSparseGrid_isHipEnabled") & result(fresult) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_isDpcppEnabled() & bind(C, name="_wrap_TasmanianSparseGrid_isDpcppEnabled") & result(fresult) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: fresult end function subroutine swigc_TasmanianSparseGrid_write__SWIG_0(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_write__SWIG_0") use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigArrayWrapper) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_write__SWIG_1(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_write__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigArrayWrapper) :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_read__SWIG_0(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_read__SWIG_0") use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigArrayWrapper) :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_5(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, & farg10, farg11) & bind(C, name="_wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_5") use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 type(C_PTR), value :: farg7 real(C_DOUBLE), intent(in) :: farg8 real(C_DOUBLE), intent(in) :: farg9 type(SwigArrayWrapper) :: farg10 type(C_PTR), value :: farg11 end subroutine subroutine swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_6(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, & farg10) & bind(C, name="_wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_6") use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 type(C_PTR), value :: farg7 real(C_DOUBLE), intent(in) :: farg8 real(C_DOUBLE), intent(in) :: farg9 type(SwigArrayWrapper) :: farg10 end subroutine subroutine swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_7(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) & bind(C, name="_wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_7") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 type(C_PTR), value :: farg7 real(C_DOUBLE), intent(in) :: farg8 real(C_DOUBLE), intent(in) :: farg9 end subroutine subroutine swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_8(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8) & bind(C, name="_wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_8") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 type(C_PTR), value :: farg7 real(C_DOUBLE), intent(in) :: farg8 end subroutine subroutine swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_9(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & bind(C, name="_wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_9") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 type(C_PTR), value :: farg7 end subroutine subroutine swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_10(farg1, farg2, farg3, farg4, farg5, farg6) & bind(C, name="_wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_10") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 end subroutine subroutine swigc_TasmanianSparseGrid_makeSequenceGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8) & bind(C, name="_wrap_TasmanianSparseGrid_makeSequenceGrid__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 type(C_PTR), value :: farg7 type(C_PTR), value :: farg8 end subroutine subroutine swigc_TasmanianSparseGrid_makeSequenceGrid__SWIG_3(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & bind(C, name="_wrap_TasmanianSparseGrid_makeSequenceGrid__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 type(C_PTR), value :: farg7 end subroutine subroutine swigc_TasmanianSparseGrid_makeSequenceGrid__SWIG_4(farg1, farg2, farg3, farg4, farg5, farg6) & bind(C, name="_wrap_TasmanianSparseGrid_makeSequenceGrid__SWIG_4") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 end subroutine subroutine swigc_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_1(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & bind(C, name="_wrap_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 type(C_PTR), value :: farg7 end subroutine subroutine swigc_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5, farg6) & bind(C, name="_wrap_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 integer(C_INT), intent(in) :: farg6 end subroutine subroutine swigc_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_3(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 end subroutine subroutine swigc_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_4(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_4") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_makeWaveletGrid__SWIG_1(farg1, farg2, farg3, farg4, farg5, farg6) & bind(C, name="_wrap_TasmanianSparseGrid_makeWaveletGrid__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 type(C_PTR), value :: farg6 end subroutine subroutine swigc_TasmanianSparseGrid_makeWaveletGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_TasmanianSparseGrid_makeWaveletGrid__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 end subroutine subroutine swigc_TasmanianSparseGrid_makeWaveletGrid__SWIG_3(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_makeWaveletGrid__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_makeFourierGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5, farg6, farg7) & bind(C, name="_wrap_TasmanianSparseGrid_makeFourierGrid__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 type(C_PTR), value :: farg6 type(C_PTR), value :: farg7 end subroutine subroutine swigc_TasmanianSparseGrid_makeFourierGrid__SWIG_3(farg1, farg2, farg3, farg4, farg5, farg6) & bind(C, name="_wrap_TasmanianSparseGrid_makeFourierGrid__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 type(C_PTR), value :: farg6 end subroutine subroutine swigc_TasmanianSparseGrid_makeFourierGrid__SWIG_4(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_TasmanianSparseGrid_makeFourierGrid__SWIG_4") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 integer(C_INT), intent(in) :: farg5 end subroutine subroutine swigc_TasmanianSparseGrid_copyGrid__SWIG_0(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_copyGrid__SWIG_0") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigClassWrapper), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_copyGrid__SWIG_1(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_copyGrid__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigClassWrapper), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_copyGrid__SWIG_2(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_copyGrid__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigClassWrapper), intent(in) :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_updateGlobalGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_TasmanianSparseGrid_updateGlobalGrid__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 type(C_PTR), value :: farg5 end subroutine subroutine swigc_TasmanianSparseGrid_updateGlobalGrid__SWIG_3(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_updateGlobalGrid__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_updateGlobalGrid__SWIG_4(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_updateGlobalGrid__SWIG_4") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_updateSequenceGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_TasmanianSparseGrid_updateSequenceGrid__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 type(C_PTR), value :: farg5 end subroutine subroutine swigc_TasmanianSparseGrid_updateSequenceGrid__SWIG_3(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_updateSequenceGrid__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_updateSequenceGrid__SWIG_4(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_updateSequenceGrid__SWIG_4") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_updateFourierGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_TasmanianSparseGrid_updateFourierGrid__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 type(C_PTR), value :: farg5 end subroutine subroutine swigc_TasmanianSparseGrid_updateFourierGrid__SWIG_3(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_updateFourierGrid__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_updateFourierGrid__SWIG_4(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_updateFourierGrid__SWIG_4") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_updateGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_TasmanianSparseGrid_updateGrid__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 type(C_PTR), value :: farg5 end subroutine subroutine swigc_TasmanianSparseGrid_updateGrid__SWIG_3(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_updateGrid__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_updateGrid__SWIG_4(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_updateGrid__SWIG_4") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine function swigc_TasmanianSparseGrid_getAlpha(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getAlpha") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 real(C_DOUBLE) :: fresult end function function swigc_TasmanianSparseGrid_getBeta(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getBeta") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 real(C_DOUBLE) :: fresult end function function swigc_TasmanianSparseGrid_getOrder(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getOrder") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getNumDimensions(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getNumDimensions") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getNumOutputs(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getNumOutputs") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getRule(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getRule") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getCustomRuleDescription(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getCustomRuleDescription") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigArrayWrapper) :: fresult end function function swigc_TasmanianSparseGrid_getNumLoaded(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getNumLoaded") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getNumNeeded(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getNumNeeded") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getNumPoints(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getNumPoints") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function subroutine swigc_TasmanianSparseGrid_getLoadedPoints__SWIG_2(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_getLoadedPoints__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_getNeededPoints__SWIG_2(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_getNeededPoints__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_getPoints__SWIG_2(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_getPoints__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_getQuadratureWeights__SWIG_2(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_getQuadratureWeights__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_getInterpolationWeights__SWIG_3(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_getInterpolationWeights__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 type(C_PTR), value :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_getDifferentiationWeights__SWIG_3(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_getDifferentiationWeights__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 type(C_PTR), value :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_loadNeededValues__SWIG_1(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_loadNeededValues__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_loadNeededPoints__SWIG_1(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_loadNeededPoints__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_evaluate__SWIG_1(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_evaluate__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 type(C_PTR), value :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_evaluateBatch__SWIG_0(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_evaluateBatch__SWIG_0") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_evaluateBatch__SWIG_1(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_evaluateBatch__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_integrate__SWIG_1(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_integrate__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_differentiate__SWIG_2(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_differentiate__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 type(C_PTR), value :: farg3 end subroutine function swigc_TasmanianSparseGrid_isGlobal(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_isGlobal") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_isSequence(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_isSequence") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_isLocalPolynomial(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_isLocalPolynomial") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_isWavelet(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_isWavelet") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_isFourier(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_isFourier") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_isEmpty(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_isEmpty") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_empty(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_empty") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function subroutine swigc_TasmanianSparseGrid_setDomainTransform__SWIG_1(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_setDomainTransform__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 type(C_PTR), value :: farg3 end subroutine function swigc_TasmanianSparseGrid_isSetDomainTransfrom(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_isSetDomainTransfrom") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function subroutine swigc_TasmanianSparseGrid_clearDomainTransform(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_clearDomainTransform") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 end subroutine subroutine swigc_TasmanianSparseGrid_getDomainTransform__SWIG_1(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_getDomainTransform__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 type(C_PTR), value :: farg3 end subroutine function swigc_TasmanianSparseGrid_isSetConformalTransformASIN(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_isSetConformalTransformASIN") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function subroutine swigc_TasmanianSparseGrid_clearConformalTransform(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_clearConformalTransform") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 end subroutine subroutine swigc_TasmanianSparseGrid_clearLevelLimits(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_clearLevelLimits") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 end subroutine subroutine swigc_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_1(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 type(C_PTR), value :: farg5 end subroutine subroutine swigc_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_2(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_setSurplusRefinement__SWIG_3(farg1, farg2, farg3, farg4, farg5, farg6) & bind(C, name="_wrap_TasmanianSparseGrid_setSurplusRefinement__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 real(C_DOUBLE), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 type(C_PTR), value :: farg5 type(C_PTR), value :: farg6 end subroutine subroutine swigc_TasmanianSparseGrid_setSurplusRefinement__SWIG_4(farg1, farg2, farg3, farg4, farg5) & bind(C, name="_wrap_TasmanianSparseGrid_setSurplusRefinement__SWIG_4") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 real(C_DOUBLE), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 type(C_PTR), value :: farg5 end subroutine subroutine swigc_TasmanianSparseGrid_setSurplusRefinement__SWIG_5(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_setSurplusRefinement__SWIG_5") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 real(C_DOUBLE), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT), intent(in) :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_setSurplusRefinement__SWIG_6(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_setSurplusRefinement__SWIG_6") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 real(C_DOUBLE), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_clearRefinement(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_clearRefinement") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 end subroutine subroutine swigc_TasmanianSparseGrid_mergeRefinement(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_mergeRefinement") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 end subroutine subroutine swigc_TasmanianSparseGrid_getHierarchicalCoefficientsStatic(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_getHierarchicalCoefficientsStatic") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_setHierarchicalCoefficients__SWIG_1(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_setHierarchicalCoefficients__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_evaluateHierarchicalFunctions__SWIG_2(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_evaluateHierarchicalFunctions__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_integrateHierarchicalFu1JSVB3__SWIG_2(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_integrateHierarchicalFunctions__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_printStats__SWIG_1(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_printStats__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 end subroutine subroutine swigc_TasmanianSparseGrid_enableAcceleration__SWIG_0(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_enableAcceleration__SWIG_0") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_enableAcceleration__SWIG_1(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_enableAcceleration__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_favorSparseAcceleration(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_favorSparseAcceleration") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 end subroutine function swigc_TasmanianSparseGrid_getAccelerationType(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getAccelerationType") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_isAccelerationAvailable(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_isAccelerationAvailable") & result(fresult) use, intrinsic :: ISO_C_BINDING integer(C_INT), intent(in) :: farg1 integer(C_INT) :: fresult end function subroutine swigc_TasmanianSparseGrid_setGPUID(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_setGPUID") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 end subroutine function swigc_TasmanianSparseGrid_getGPUID(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getGPUID") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getNumGPUs() & bind(C, name="_wrap_TasmanianSparseGrid_getNumGPUs") & result(fresult) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getGPUMemory(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getGPUMemory") & result(fresult) use, intrinsic :: ISO_C_BINDING integer(C_INT), intent(in) :: farg1 integer(C_INT) :: fresult end function function swigc_TasmanianSparseGrid_getGPUName(farg1) & bind(C, name="_wrap_TasmanianSparseGrid_getGPUName") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper integer(C_INT), intent(in) :: farg1 type(SwigArrayWrapper) :: fresult end function subroutine swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_0(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_0") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 real(C_DOUBLE), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_1(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 real(C_DOUBLE), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_2(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 real(C_DOUBLE), intent(in) :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_3(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_3") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_4(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_4") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_5(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_5") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 end subroutine function swigc_TasmanianSparseGrid_evaluateSparseHierarchicalFunct1CQM1I(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_evaluateSparseHierarchicalFunctionsGetNZ") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 integer(C_INT), intent(in) :: farg3 integer(C_INT) :: fresult end function subroutine swigc_TasmanianSparseGrid_evaluateSparseHierarchicalFunct1HRJEE(farg1, farg2, farg3, farg4, farg5, farg6) & bind(C, name="_wrap_TasmanianSparseGrid_evaluateSparseHierarchicalFunctionsStatic") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 type(C_PTR), value :: farg5 type(C_PTR), value :: farg6 end subroutine subroutine swigc_TasmanianSparseGrid_evaluateFast__SWIG_0(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_evaluateFast__SWIG_0") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 type(C_PTR), value :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_evaluateFast__SWIG_2(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianSparseGrid_evaluateFast__SWIG_2") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 type(C_PTR), value :: farg3 end subroutine subroutine swigc_TasmanianSparseGrid_evaluateBatchGPU__SWIG_0(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_evaluateBatchGPU__SWIG_0") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_evaluateBatchGPU__SWIG_1(farg1, farg2, farg3, farg4) & bind(C, name="_wrap_TasmanianSparseGrid_evaluateBatchGPU__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 integer(C_INT), intent(in) :: farg3 type(C_PTR), value :: farg4 end subroutine subroutine swigc_TasmanianSparseGrid_setConformalTransformASIN__SWIG_1(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_setConformalTransformASIN__SWIG_1") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(C_PTR), value :: farg2 end subroutine subroutine swigc_TasmanianSparseGrid_op_assign__(farg1, farg2) & bind(C, name="_wrap_TasmanianSparseGrid_op_assign__") use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(inout) :: farg1 type(SwigClassWrapper), intent(in) :: farg2 end subroutine function swigc_TasmanianReadGrid(farg1) & bind(C, name="_wrap_TasmanianReadGrid") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigarraywrapper import :: swigclasswrapper type(SwigArrayWrapper) :: farg1 type(SwigClassWrapper) :: fresult end function function swigc_TasmanianCopyGrid__SWIG_0(farg1, farg2, farg3) & bind(C, name="_wrap_TasmanianCopyGrid__SWIG_0") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 integer(C_INT), intent(in) :: farg3 type(SwigClassWrapper) :: fresult end function function swigc_TasmanianCopyGrid__SWIG_1(farg1, farg2) & bind(C, name="_wrap_TasmanianCopyGrid__SWIG_1") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 integer(C_INT), intent(in) :: farg2 type(SwigClassWrapper) :: fresult end function function swigc_TasmanianCopyGrid__SWIG_2(farg1) & bind(C, name="_wrap_TasmanianCopyGrid__SWIG_2") & result(fresult) use, intrinsic :: ISO_C_BINDING import :: swigclasswrapper type(SwigClassWrapper), intent(in) :: farg1 type(SwigClassWrapper) :: fresult end function end interface contains ! MODULE SUBPROGRAMS subroutine SWIGTM_fout_char_Sm_(imout, fout) use, intrinsic :: ISO_C_BINDING type(SwigArrayWrapper), intent(in) :: imout character(len=:), allocatable, intent(out) :: fout character(kind=C_CHAR), dimension(:), pointer :: chars integer(kind=C_SIZE_T) :: i call c_f_pointer(imout%data, chars, [imout%size]) allocate(character(len=imout%size) :: fout) do i=1, imout%size fout(i:i) = char(ichar(chars(i))) end do end subroutine function get_serr() & result(swig_result) use, intrinsic :: ISO_C_BINDING character(len=:), allocatable :: swig_result type(SwigArrayWrapper) :: fresult fresult = swigc_get_serr() call SWIGTM_fout_char_Sm_(fresult, swig_result) if (.false.) call SWIG_free(fresult%data) end function function TasmanianGlobalGrid(dims, outs, depth, gtype, rule, & aweights, alpha, beta, custom_filename, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT), intent(in) :: dims, outs, depth, gtype, rule integer(C_INT), optional, target :: aweights(:) double precision, optional :: alpha, beta character(len=*), target, optional :: custom_filename integer(C_INT), optional :: level_limits(dims) real(C_DOUBLE) :: al, be integer(C_INT), dimension(:), pointer :: aw(:) if ( present(aweights) ) then aw => aweights else allocate(aw(2 * dims)) aw(1:dims) = 1; aw(dims+1:2*dims) = 0; endif if ( present(alpha) ) then al = alpha else al = 0.0D-0 endif if ( present(beta) ) then be = beta else be = 0.0D-0 endif grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(custom_filename) ) then if ( present(level_limits) ) then call grid%makeGlobalGrid(dims, outs, depth, gtype, rule, aw, al, be, custom_filename, level_limits) else call grid%makeGlobalGrid(dims, outs, depth, gtype, rule, aw, al, be, custom_filename) endif else if ( present(level_limits) ) then call grid%makeGlobalGrid(dims, outs, depth, gtype, rule, aw, al, be, "", level_limits) else call grid%makeGlobalGrid(dims, outs, depth, gtype, rule, aw, al, be) endif endif if ( .not. present(aweights) ) then deallocate(aw) endif end function function TasmanianSequenceGrid(dims, outs, depth, gtype, rule, aweights, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT) :: dims, outs, depth, gtype, rule integer(C_INT), optional, target :: aweights(:) integer(C_INT), optional :: level_limits(dims) integer(C_INT) :: aw(2 * dims) grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(aweights) ) then if ( present(level_limits) ) then call grid%makeSequenceGrid(dims, outs, depth, gtype, rule, aweights, level_limits) else call grid%makeSequenceGrid(dims, outs, depth, gtype, rule, aweights) endif else if ( present(level_limits) ) then aw(1:dims) = 1; aw(dims+1:2*dims) = 0; call grid%makeSequenceGrid(dims, outs, depth, gtype, rule, aw, level_limits) else call grid%makeSequenceGrid(dims, outs, depth, gtype, rule) endif endif end function function TasmanianLocalPolynomialGrid(dims, outs, depth, order, rule, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT) :: dims, outs, depth, ord, ru integer(C_INT), optional :: order, rule integer(C_INT), optional :: level_limits(dims) if ( present(order) ) then ord = order else ord = 1 endif if ( present(rule) ) then ru = rule else ru = tsg_rule_localp endif grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(level_limits) ) then call grid%makeLocalPolynomialGrid(dims, outs, depth, ord, ru, level_limits) else call grid%makeLocalPolynomialGrid(dims, outs, depth, ord, ru) endif end function function TasmanianWaveletGrid(dims, outs, depth, order, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT) :: dims, outs, depth, ord integer(C_INT), optional :: order integer(C_INT), optional :: level_limits(dims) if ( present(order) ) then ord = order else ord = 1 endif grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(level_limits) ) then call grid%makeWaveletGrid(dims, outs, depth, ord, level_limits) else call grid%makeWaveletGrid(dims, outs, depth, ord) endif end function function TasmanianFourierGrid(dims, outs, depth, gtype, aweights, level_limits) result(grid) type(TasmanianSparseGrid) :: grid integer(C_INT) :: dims, outs, depth, gtype integer(C_INT), dimension(:), optional :: aweights(:) integer(C_INT), optional :: level_limits(dims) integer(C_INT) :: aw(2 * dims) grid%swigdata = swigc_new_TasmanianSparseGrid__SWIG_0() if ( present(aweights) ) then if ( present(level_limits) ) then call grid%makeFourierGrid(dims, outs, depth, gtype, aweights, level_limits) else call grid%makeFourierGrid(dims, outs, depth, gtype, aweights) endif else if ( present(level_limits) ) then aw(1:dims) = 1; aw(dims+1:2*dims) = 0; call grid%makeFourierGrid(dims, outs, depth, gtype, aw, level_limits) else call grid%makeFourierGrid(dims, outs, depth, gtype) endif endif end function function tsgGetLoadedPoints(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:,:), pointer :: fresult allocate(fresult(grid%getNumDimensions(), grid%getNumLoaded())) call grid%getLoadedPoints(fresult(:,1)) end function function tsgGetNeededPoints(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:,:), pointer :: fresult allocate(fresult(grid%getNumDimensions(), grid%getNumNeeded())) call grid%getNeededPoints(fresult(:,1)) end function function tsgGetPoints(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:,:), pointer :: fresult allocate(fresult(grid%getNumDimensions(), grid%getNumPoints())) call grid%getPoints(fresult(:,1)) end function function tsgGetQuadratureWeights(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:), pointer :: fresult allocate(fresult(grid%getNumPoints())) call grid%getQuadratureWeights(fresult) end function function tsgGetHierarchicalCoefficients(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:, :), pointer :: fresult if (grid%isFourier()) then allocate(fresult(grid%getNumOutputs(), 2 * grid%getNumLoaded())) else allocate(fresult(grid%getNumOutputs(), grid%getNumLoaded())) endif call grid%getHierarchicalCoefficientsStatic(fresult(:,1)) end function function tsgGetComplexHierarchicalCoefficients(grid) result(fresult) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: grid real(C_DOUBLE), dimension(:, :), pointer :: real_coeff complex(C_DOUBLE_COMPLEX), dimension(:, :), pointer :: fresult integer :: i, j, numo, numl real_coeff => tsgGetHierarchicalCoefficients(grid) numl = grid%getNumLoaded() numo = grid%getNumOutputs() allocate(fresult(numo, numl)) do i = 1, numl do j = 1, numo fresult(j,i) = cmplx(real_coeff(j,i), real_coeff(j,i + numl), 8) enddo enddo deallocate(real_coeff) end function subroutine tsgSetComplexHierarchicalCoefficients(grid, coeffs) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(inout) :: grid complex(C_DOUBLE_COMPLEX), dimension(:, :) :: coeffs real(C_DOUBLE), dimension(:, :), pointer :: real_coeff integer :: i, j, numo, numl numl = grid%getNumPoints() numo = grid%getNumOutputs() allocate(real_coeff(numo, 2*numl)) do i = 1, numl do j = 1, numo real_coeff(j,i) = real(coeffs(j,i), 8) real_coeff(j,i + numl) = aimag(coeffs(j,i)) enddo enddo call grid%setHierarchicalCoefficients(real_coeff(:,1)) deallocate(real_coeff) end subroutine function swigf_new_TasmanianSparseGrid__SWIG_0() & result(self) use, intrinsic :: ISO_C_BINDING type(TasmanianSparseGrid) :: self type(SwigClassWrapper) :: fresult fresult = swigc_new_TasmanianSparseGrid__SWIG_0() self%swigdata = fresult end function function swigf_new_TasmanianSparseGrid__SWIG_1(source) & result(self) use, intrinsic :: ISO_C_BINDING type(TasmanianSparseGrid) :: self class(TasmanianSparseGrid), intent(in) :: source type(SwigClassWrapper) :: fresult type(SwigClassWrapper) :: farg1 farg1 = source%swigdata fresult = swigc_new_TasmanianSparseGrid__SWIG_1(farg1) self%swigdata = fresult end function subroutine swigf_TasmanianSparseGrid_release(self) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(inout) :: self type(SwigClassWrapper) :: farg1 farg1 = self%swigdata if (btest(farg1%cmemflags, swig_cmem_own_bit)) then call swigc_delete_TasmanianSparseGrid(farg1) endif farg1%cptr = C_NULL_PTR farg1%cmemflags = 0 self%swigdata = farg1 end subroutine function swigf_TasmanianSparseGrid_getVersion() & result(swig_result) use, intrinsic :: ISO_C_BINDING character(len=:), allocatable :: swig_result type(SwigArrayWrapper) :: fresult fresult = swigc_TasmanianSparseGrid_getVersion() call SWIGTM_fout_char_Sm_(fresult, swig_result) if (.false.) call SWIG_free(fresult%data) end function function swigf_TasmanianSparseGrid_getVersionMajor() & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result integer(C_INT) :: fresult fresult = swigc_TasmanianSparseGrid_getVersionMajor() swig_result = fresult end function function swigf_TasmanianSparseGrid_getVersionMinor() & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result integer(C_INT) :: fresult fresult = swigc_TasmanianSparseGrid_getVersionMinor() swig_result = fresult end function function swigf_TasmanianSparseGrid_getLicense() & result(swig_result) use, intrinsic :: ISO_C_BINDING character(len=:), allocatable :: swig_result type(SwigArrayWrapper) :: fresult fresult = swigc_TasmanianSparseGrid_getLicense() call SWIGTM_fout_char_Sm_(fresult, swig_result) if (.false.) call SWIG_free(fresult%data) end function function swigf_TasmanianSparseGrid_getGitCommitHash() & result(swig_result) use, intrinsic :: ISO_C_BINDING character(len=:), allocatable :: swig_result type(SwigArrayWrapper) :: fresult fresult = swigc_TasmanianSparseGrid_getGitCommitHash() call SWIGTM_fout_char_Sm_(fresult, swig_result) if (.false.) call SWIG_free(fresult%data) end function function swigf_TasmanianSparseGrid_getCmakeCxxFlags() & result(swig_result) use, intrinsic :: ISO_C_BINDING character(len=:), allocatable :: swig_result type(SwigArrayWrapper) :: fresult fresult = swigc_TasmanianSparseGrid_getCmakeCxxFlags() call SWIGTM_fout_char_Sm_(fresult, swig_result) if (.false.) call SWIG_free(fresult%data) end function subroutine SWIGTM_fout_bool(imout, fout) use, intrinsic :: ISO_C_BINDING integer(kind=C_INT), intent(in) :: imout logical, intent(out) :: fout fout = (imout /= 0) end subroutine function swigf_TasmanianSparseGrid_isOpenMPEnabled() & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result integer(C_INT) :: fresult fresult = swigc_TasmanianSparseGrid_isOpenMPEnabled() call SWIGTM_fout_bool(fresult, swig_result) end function function swigf_TasmanianSparseGrid_isCudaEnabled() & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result integer(C_INT) :: fresult fresult = swigc_TasmanianSparseGrid_isCudaEnabled() call SWIGTM_fout_bool(fresult, swig_result) end function function swigf_TasmanianSparseGrid_isHipEnabled() & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result integer(C_INT) :: fresult fresult = swigc_TasmanianSparseGrid_isHipEnabled() call SWIGTM_fout_bool(fresult, swig_result) end function function swigf_TasmanianSparseGrid_isDpcppEnabled() & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result integer(C_INT) :: fresult fresult = swigc_TasmanianSparseGrid_isDpcppEnabled() call SWIGTM_fout_bool(fresult, swig_result) end function subroutine SWIGTM_fin_char_Sm_(finp, iminp, temp) use, intrinsic :: ISO_C_BINDING character(len=*), intent(in) :: finp type(SwigArrayWrapper), intent(out) :: iminp character(kind=C_CHAR), dimension(:), target, allocatable, intent(out) :: temp integer :: i allocate(character(kind=C_CHAR) :: temp(len(finp) + 1)) do i=1,len(finp) temp(i) = char(ichar(finp(i:i)), kind=C_CHAR) end do i = len(finp) + 1 temp(i) = C_NULL_CHAR ! C finp compatibility iminp%data = c_loc(temp) iminp%size = len(finp, kind=C_SIZE_T) end subroutine subroutine SWIGTM_fin_bool(finp, iminp) use, intrinsic :: ISO_C_BINDING logical, intent(in) :: finp integer(kind=C_INT), intent(out) :: iminp if (finp .eqv. .true.) then iminp = 1 else iminp = 0 end if end subroutine subroutine swigf_TasmanianSparseGrid_write__SWIG_0(self, filename, binary) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self character(len=*), intent(in) :: filename logical, intent(in) :: binary type(SwigClassWrapper) :: farg1 character(kind=C_CHAR), dimension(:), allocatable, target :: farg2_temp type(SwigArrayWrapper) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata call SWIGTM_fin_char_Sm_(filename, farg2, farg2_temp) call SWIGTM_fin_bool(binary, farg3) call swigc_TasmanianSparseGrid_write__SWIG_0(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_write__SWIG_1(self, filename) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self character(len=*), intent(in) :: filename type(SwigClassWrapper) :: farg1 character(kind=C_CHAR), dimension(:), allocatable, target :: farg2_temp type(SwigArrayWrapper) :: farg2 farg1 = self%swigdata call SWIGTM_fin_char_Sm_(filename, farg2, farg2_temp) call swigc_TasmanianSparseGrid_write__SWIG_1(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_read__SWIG_0(self, filename) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self character(len=*), intent(in) :: filename type(SwigClassWrapper) :: farg1 character(kind=C_CHAR), dimension(:), allocatable, target :: farg2_temp type(SwigArrayWrapper) :: farg2 farg1 = self%swigdata call SWIGTM_fin_char_Sm_(filename, farg2, farg2_temp) call swigc_TasmanianSparseGrid_read__SWIG_0(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_5(self, dimensions, outputs, depth, type, rule, anisotropic_weights, & alpha, beta, custom_filename, level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(tsg_TypeOneDRule), intent(in) :: rule integer(C_INT), dimension(*), target :: anisotropic_weights real(C_DOUBLE), intent(in) :: alpha real(C_DOUBLE), intent(in) :: beta character(len=*), intent(in) :: custom_filename integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 type(C_PTR) :: farg7 real(C_DOUBLE) :: farg8 real(C_DOUBLE) :: farg9 character(kind=C_CHAR), dimension(:), allocatable, target :: farg10_temp type(SwigArrayWrapper) :: farg10 type(C_PTR) :: farg11 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = rule farg7 = c_loc(anisotropic_weights) farg8 = alpha farg9 = beta call SWIGTM_fin_char_Sm_(custom_filename, farg10, farg10_temp) farg11 = c_loc(level_limits) call swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_5(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10, & farg11) end subroutine subroutine swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_6(self, dimensions, outputs, depth, type, rule, anisotropic_weights, & alpha, beta, custom_filename) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(tsg_TypeOneDRule), intent(in) :: rule integer(C_INT), dimension(*), target :: anisotropic_weights real(C_DOUBLE), intent(in) :: alpha real(C_DOUBLE), intent(in) :: beta character(len=*), intent(in) :: custom_filename type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 type(C_PTR) :: farg7 real(C_DOUBLE) :: farg8 real(C_DOUBLE) :: farg9 character(kind=C_CHAR), dimension(:), allocatable, target :: farg10_temp type(SwigArrayWrapper) :: farg10 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = rule farg7 = c_loc(anisotropic_weights) farg8 = alpha farg9 = beta call SWIGTM_fin_char_Sm_(custom_filename, farg10, farg10_temp) call swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_6(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9, farg10) end subroutine subroutine swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_7(self, dimensions, outputs, depth, type, rule, anisotropic_weights, & alpha, beta) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(tsg_TypeOneDRule), intent(in) :: rule integer(C_INT), dimension(*), target :: anisotropic_weights real(C_DOUBLE), intent(in) :: alpha real(C_DOUBLE), intent(in) :: beta type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 type(C_PTR) :: farg7 real(C_DOUBLE) :: farg8 real(C_DOUBLE) :: farg9 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = rule farg7 = c_loc(anisotropic_weights) farg8 = alpha farg9 = beta call swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_7(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8, farg9) end subroutine subroutine swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_8(self, dimensions, outputs, depth, type, rule, anisotropic_weights, & alpha) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(tsg_TypeOneDRule), intent(in) :: rule integer(C_INT), dimension(*), target :: anisotropic_weights real(C_DOUBLE), intent(in) :: alpha type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 type(C_PTR) :: farg7 real(C_DOUBLE) :: farg8 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = rule farg7 = c_loc(anisotropic_weights) farg8 = alpha call swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_8(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8) end subroutine subroutine swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_9(self, dimensions, outputs, depth, type, rule, anisotropic_weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(tsg_TypeOneDRule), intent(in) :: rule integer(C_INT), dimension(*), target :: anisotropic_weights type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 type(C_PTR) :: farg7 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = rule farg7 = c_loc(anisotropic_weights) call swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_9(farg1, farg2, farg3, farg4, farg5, farg6, farg7) end subroutine subroutine swigf_TasmanianSparseGrid_makeGlobalGrid__SWIG_10(self, dimensions, outputs, depth, type, rule) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(tsg_TypeOneDRule), intent(in) :: rule type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = rule call swigc_TasmanianSparseGrid_makeGlobalGrid__SWIG_10(farg1, farg2, farg3, farg4, farg5, farg6) end subroutine subroutine swigf_TasmanianSparseGrid_makeSequenceGrid__SWIG_2(self, dimensions, outputs, depth, type, rule, & anisotropic_weights, level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(tsg_TypeOneDRule), intent(in) :: rule integer(C_INT), dimension(*), target :: anisotropic_weights integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 type(C_PTR) :: farg7 type(C_PTR) :: farg8 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = rule farg7 = c_loc(anisotropic_weights) farg8 = c_loc(level_limits) call swigc_TasmanianSparseGrid_makeSequenceGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5, farg6, farg7, farg8) end subroutine subroutine swigf_TasmanianSparseGrid_makeSequenceGrid__SWIG_3(self, dimensions, outputs, depth, type, rule, & anisotropic_weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(tsg_TypeOneDRule), intent(in) :: rule integer(C_INT), dimension(*), target :: anisotropic_weights type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 type(C_PTR) :: farg7 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = rule farg7 = c_loc(anisotropic_weights) call swigc_TasmanianSparseGrid_makeSequenceGrid__SWIG_3(farg1, farg2, farg3, farg4, farg5, farg6, farg7) end subroutine subroutine swigf_TasmanianSparseGrid_makeSequenceGrid__SWIG_4(self, dimensions, outputs, depth, type, rule) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(tsg_TypeOneDRule), intent(in) :: rule type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = rule call swigc_TasmanianSparseGrid_makeSequenceGrid__SWIG_4(farg1, farg2, farg3, farg4, farg5, farg6) end subroutine subroutine swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_1(self, dimensions, outputs, depth, order, rule, & level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(C_INT), intent(in) :: order integer(tsg_TypeOneDRule), intent(in) :: rule integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 type(C_PTR) :: farg7 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = order farg6 = rule farg7 = c_loc(level_limits) call swigc_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_1(farg1, farg2, farg3, farg4, farg5, farg6, farg7) end subroutine subroutine swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_2(self, dimensions, outputs, depth, order, rule) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(C_INT), intent(in) :: order integer(tsg_TypeOneDRule), intent(in) :: rule type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 integer(C_INT) :: farg6 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = order farg6 = rule call swigc_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5, farg6) end subroutine subroutine swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_3(self, dimensions, outputs, depth, order) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(C_INT), intent(in) :: order type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = order call swigc_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_3(farg1, farg2, farg3, farg4, farg5) end subroutine subroutine swigf_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_4(self, dimensions, outputs, depth) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth call swigc_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_4(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_makeWaveletGrid__SWIG_1(self, dimensions, outputs, depth, order, level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(C_INT), intent(in) :: order integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 type(C_PTR) :: farg6 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = order farg6 = c_loc(level_limits) call swigc_TasmanianSparseGrid_makeWaveletGrid__SWIG_1(farg1, farg2, farg3, farg4, farg5, farg6) end subroutine subroutine swigf_TasmanianSparseGrid_makeWaveletGrid__SWIG_2(self, dimensions, outputs, depth, order) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(C_INT), intent(in) :: order type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = order call swigc_TasmanianSparseGrid_makeWaveletGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) end subroutine subroutine swigf_TasmanianSparseGrid_makeWaveletGrid__SWIG_3(self, dimensions, outputs, depth) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth call swigc_TasmanianSparseGrid_makeWaveletGrid__SWIG_3(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_makeFourierGrid__SWIG_2(self, dimensions, outputs, depth, type, anisotropic_weights, & level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 type(C_PTR) :: farg6 type(C_PTR) :: farg7 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = c_loc(anisotropic_weights) farg7 = c_loc(level_limits) call swigc_TasmanianSparseGrid_makeFourierGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5, farg6, farg7) end subroutine subroutine swigf_TasmanianSparseGrid_makeFourierGrid__SWIG_3(self, dimensions, outputs, depth, type, anisotropic_weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 type(C_PTR) :: farg6 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type farg6 = c_loc(anisotropic_weights) call swigc_TasmanianSparseGrid_makeFourierGrid__SWIG_3(farg1, farg2, farg3, farg4, farg5, farg6) end subroutine subroutine swigf_TasmanianSparseGrid_makeFourierGrid__SWIG_4(self, dimensions, outputs, depth, type) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: dimensions integer(C_INT), intent(in) :: outputs integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 integer(C_INT) :: farg5 farg1 = self%swigdata farg2 = dimensions farg3 = outputs farg4 = depth farg5 = type call swigc_TasmanianSparseGrid_makeFourierGrid__SWIG_4(farg1, farg2, farg3, farg4, farg5) end subroutine subroutine swigf_TasmanianSparseGrid_copyGrid__SWIG_0(self, source, outputs_begin, outputs_end) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self class(TasmanianSparseGrid), intent(in) :: source integer(C_INT), intent(in) :: outputs_begin integer(C_INT), intent(in) :: outputs_end type(SwigClassWrapper) :: farg1 type(SwigClassWrapper) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 farg1 = self%swigdata farg2 = source%swigdata farg3 = outputs_begin farg4 = outputs_end call swigc_TasmanianSparseGrid_copyGrid__SWIG_0(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_copyGrid__SWIG_1(self, source, outputs_begin) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self class(TasmanianSparseGrid), intent(in) :: source integer(C_INT), intent(in) :: outputs_begin type(SwigClassWrapper) :: farg1 type(SwigClassWrapper) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = source%swigdata farg3 = outputs_begin call swigc_TasmanianSparseGrid_copyGrid__SWIG_1(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_copyGrid__SWIG_2(self, source) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self class(TasmanianSparseGrid), intent(in) :: source type(SwigClassWrapper) :: farg1 type(SwigClassWrapper) :: farg2 farg1 = self%swigdata farg2 = source%swigdata call swigc_TasmanianSparseGrid_copyGrid__SWIG_2(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_updateGlobalGrid__SWIG_2(self, depth, type, anisotropic_weights, level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 type(C_PTR) :: farg5 farg1 = self%swigdata farg2 = depth farg3 = type farg4 = c_loc(anisotropic_weights) farg5 = c_loc(level_limits) call swigc_TasmanianSparseGrid_updateGlobalGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) end subroutine subroutine swigf_TasmanianSparseGrid_updateGlobalGrid__SWIG_3(self, depth, type, anisotropic_weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = depth farg3 = type farg4 = c_loc(anisotropic_weights) call swigc_TasmanianSparseGrid_updateGlobalGrid__SWIG_3(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_updateGlobalGrid__SWIG_4(self, depth, type) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = depth farg3 = type call swigc_TasmanianSparseGrid_updateGlobalGrid__SWIG_4(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_updateSequenceGrid__SWIG_2(self, depth, type, anisotropic_weights, level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 type(C_PTR) :: farg5 farg1 = self%swigdata farg2 = depth farg3 = type farg4 = c_loc(anisotropic_weights) farg5 = c_loc(level_limits) call swigc_TasmanianSparseGrid_updateSequenceGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) end subroutine subroutine swigf_TasmanianSparseGrid_updateSequenceGrid__SWIG_3(self, depth, type, anisotropic_weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = depth farg3 = type farg4 = c_loc(anisotropic_weights) call swigc_TasmanianSparseGrid_updateSequenceGrid__SWIG_3(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_updateSequenceGrid__SWIG_4(self, depth, type) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = depth farg3 = type call swigc_TasmanianSparseGrid_updateSequenceGrid__SWIG_4(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_updateFourierGrid__SWIG_2(self, depth, type, anisotropic_weights, level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 type(C_PTR) :: farg5 farg1 = self%swigdata farg2 = depth farg3 = type farg4 = c_loc(anisotropic_weights) farg5 = c_loc(level_limits) call swigc_TasmanianSparseGrid_updateFourierGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) end subroutine subroutine swigf_TasmanianSparseGrid_updateFourierGrid__SWIG_3(self, depth, type, anisotropic_weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = depth farg3 = type farg4 = c_loc(anisotropic_weights) call swigc_TasmanianSparseGrid_updateFourierGrid__SWIG_3(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_updateFourierGrid__SWIG_4(self, depth, type) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = depth farg3 = type call swigc_TasmanianSparseGrid_updateFourierGrid__SWIG_4(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_updateGrid__SWIG_2(self, depth, type, anisotropic_weights, level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 type(C_PTR) :: farg5 farg1 = self%swigdata farg2 = depth farg3 = type farg4 = c_loc(anisotropic_weights) farg5 = c_loc(level_limits) call swigc_TasmanianSparseGrid_updateGrid__SWIG_2(farg1, farg2, farg3, farg4, farg5) end subroutine subroutine swigf_TasmanianSparseGrid_updateGrid__SWIG_3(self, depth, type, anisotropic_weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), dimension(*), target :: anisotropic_weights type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = depth farg3 = type farg4 = c_loc(anisotropic_weights) call swigc_TasmanianSparseGrid_updateGrid__SWIG_3(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_updateGrid__SWIG_4(self, depth, type) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: depth integer(tsg_TypeDepth), intent(in) :: type type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = depth farg3 = type call swigc_TasmanianSparseGrid_updateGrid__SWIG_4(farg1, farg2, farg3) end subroutine function swigf_TasmanianSparseGrid_getAlpha(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING real(C_DOUBLE) :: swig_result class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getAlpha(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getBeta(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING real(C_DOUBLE) :: swig_result class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getBeta(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getOrder(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getOrder(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getNumDimensions(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getNumDimensions(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getNumOutputs(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getNumOutputs(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getRule(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(tsg_TypeOneDRule) :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getRule(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getCustomRuleDescription(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING character(len=:), allocatable :: swig_result class(TasmanianSparseGrid), intent(in) :: self type(SwigArrayWrapper) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getCustomRuleDescription(farg1) call SWIGTM_fout_char_Sm_(fresult, swig_result) if (.false.) call SWIG_free(fresult%data) end function function swigf_TasmanianSparseGrid_getNumLoaded(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getNumLoaded(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getNumNeeded(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getNumNeeded(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getNumPoints(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getNumPoints(farg1) swig_result = fresult end function subroutine swigf_TasmanianSparseGrid_getLoadedPoints__SWIG_2(self, x) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(x) call swigc_TasmanianSparseGrid_getLoadedPoints__SWIG_2(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_getNeededPoints__SWIG_2(self, x) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(x) call swigc_TasmanianSparseGrid_getNeededPoints__SWIG_2(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_getPoints__SWIG_2(self, x) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(x) call swigc_TasmanianSparseGrid_getPoints__SWIG_2(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_getQuadratureWeights__SWIG_2(self, weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: weights type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(weights) call swigc_TasmanianSparseGrid_getQuadratureWeights__SWIG_2(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_getInterpolationWeights__SWIG_3(self, x, weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x real(C_DOUBLE), dimension(*), target :: weights type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 type(C_PTR) :: farg3 farg1 = self%swigdata farg2 = c_loc(x) farg3 = c_loc(weights) call swigc_TasmanianSparseGrid_getInterpolationWeights__SWIG_3(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_getDifferentiationWeights__SWIG_3(self, x, weights) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x real(C_DOUBLE), dimension(*), target :: weights type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 type(C_PTR) :: farg3 farg1 = self%swigdata farg2 = c_loc(x) farg3 = c_loc(weights) call swigc_TasmanianSparseGrid_getDifferentiationWeights__SWIG_3(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_loadNeededValues__SWIG_1(self, vals) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: vals type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(vals) call swigc_TasmanianSparseGrid_loadNeededValues__SWIG_1(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_loadNeededPoints__SWIG_1(self, vals) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: vals type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(vals) call swigc_TasmanianSparseGrid_loadNeededPoints__SWIG_1(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_evaluate__SWIG_1(self, x, y) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x real(C_DOUBLE), dimension(*), target :: y type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 type(C_PTR) :: farg3 farg1 = self%swigdata farg2 = c_loc(x) farg3 = c_loc(y) call swigc_TasmanianSparseGrid_evaluate__SWIG_1(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_evaluateBatch__SWIG_0(self, x, num_x, y) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x integer(C_INT), intent(in) :: num_x real(C_DOUBLE), dimension(*), target :: y type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = c_loc(x) farg3 = num_x farg4 = c_loc(y) call swigc_TasmanianSparseGrid_evaluateBatch__SWIG_0(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_evaluateBatch__SWIG_1(self, x, num_x, y) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_FLOAT), dimension(*), target :: x integer(C_INT), intent(in) :: num_x real(C_FLOAT), dimension(*), target :: y type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = c_loc(x) farg3 = num_x farg4 = c_loc(y) call swigc_TasmanianSparseGrid_evaluateBatch__SWIG_1(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_integrate__SWIG_1(self, q) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: q type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(q) call swigc_TasmanianSparseGrid_integrate__SWIG_1(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_differentiate__SWIG_2(self, x, jacobian) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x real(C_DOUBLE), dimension(*), target :: jacobian type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 type(C_PTR) :: farg3 farg1 = self%swigdata farg2 = c_loc(x) farg3 = c_loc(jacobian) call swigc_TasmanianSparseGrid_differentiate__SWIG_2(farg1, farg2, farg3) end subroutine function swigf_TasmanianSparseGrid_isGlobal(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_isGlobal(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function function swigf_TasmanianSparseGrid_isSequence(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_isSequence(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function function swigf_TasmanianSparseGrid_isLocalPolynomial(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_isLocalPolynomial(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function function swigf_TasmanianSparseGrid_isWavelet(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_isWavelet(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function function swigf_TasmanianSparseGrid_isFourier(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_isFourier(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function function swigf_TasmanianSparseGrid_isEmpty(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_isEmpty(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function function swigf_TasmanianSparseGrid_empty(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_empty(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function subroutine swigf_TasmanianSparseGrid_setDomainTransform__SWIG_1(self, a, b) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: a real(C_DOUBLE), dimension(*), target :: b type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 type(C_PTR) :: farg3 farg1 = self%swigdata farg2 = c_loc(a) farg3 = c_loc(b) call swigc_TasmanianSparseGrid_setDomainTransform__SWIG_1(farg1, farg2, farg3) end subroutine function swigf_TasmanianSparseGrid_isSetDomainTransfrom(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_isSetDomainTransfrom(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function subroutine swigf_TasmanianSparseGrid_clearDomainTransform(self) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self type(SwigClassWrapper) :: farg1 farg1 = self%swigdata call swigc_TasmanianSparseGrid_clearDomainTransform(farg1) end subroutine subroutine swigf_TasmanianSparseGrid_getDomainTransform__SWIG_1(self, a, b) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: a real(C_DOUBLE), dimension(*), target :: b type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 type(C_PTR) :: farg3 farg1 = self%swigdata farg2 = c_loc(a) farg3 = c_loc(b) call swigc_TasmanianSparseGrid_getDomainTransform__SWIG_1(farg1, farg2, farg3) end subroutine function swigf_TasmanianSparseGrid_isSetConformalTransformASIN(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_isSetConformalTransformASIN(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function subroutine swigf_TasmanianSparseGrid_clearConformalTransform(self) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self type(SwigClassWrapper) :: farg1 farg1 = self%swigdata call swigc_TasmanianSparseGrid_clearConformalTransform(farg1) end subroutine subroutine swigf_TasmanianSparseGrid_clearLevelLimits(self) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self type(SwigClassWrapper) :: farg1 farg1 = self%swigdata call swigc_TasmanianSparseGrid_clearLevelLimits(farg1) end subroutine subroutine swigf_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_1(self, type, min_growth, output, level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), intent(in) :: min_growth integer(C_INT), intent(in) :: output integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 type(C_PTR) :: farg5 farg1 = self%swigdata farg2 = type farg3 = min_growth farg4 = output farg5 = c_loc(level_limits) call swigc_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_1(farg1, farg2, farg3, farg4, farg5) end subroutine subroutine swigf_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_2(self, type, min_growth, output) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(tsg_TypeDepth), intent(in) :: type integer(C_INT), intent(in) :: min_growth integer(C_INT), intent(in) :: output type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 farg1 = self%swigdata farg2 = type farg3 = min_growth farg4 = output call swigc_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_2(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_3(self, tolerance, criteria, output, level_limits, & scale_correction) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), intent(in) :: tolerance integer(tsg_TypeRefinement), intent(in) :: criteria integer(C_INT), intent(in) :: output integer(C_INT), dimension(*), target :: level_limits real(C_DOUBLE), dimension(*), target :: scale_correction type(SwigClassWrapper) :: farg1 real(C_DOUBLE) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 type(C_PTR) :: farg5 type(C_PTR) :: farg6 farg1 = self%swigdata farg2 = tolerance farg3 = criteria farg4 = output farg5 = c_loc(level_limits) farg6 = c_loc(scale_correction) call swigc_TasmanianSparseGrid_setSurplusRefinement__SWIG_3(farg1, farg2, farg3, farg4, farg5, farg6) end subroutine subroutine swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_4(self, tolerance, criteria, output, level_limits) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), intent(in) :: tolerance integer(tsg_TypeRefinement), intent(in) :: criteria integer(C_INT), intent(in) :: output integer(C_INT), dimension(*), target :: level_limits type(SwigClassWrapper) :: farg1 real(C_DOUBLE) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 type(C_PTR) :: farg5 farg1 = self%swigdata farg2 = tolerance farg3 = criteria farg4 = output farg5 = c_loc(level_limits) call swigc_TasmanianSparseGrid_setSurplusRefinement__SWIG_4(farg1, farg2, farg3, farg4, farg5) end subroutine subroutine swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_5(self, tolerance, criteria, output) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), intent(in) :: tolerance integer(tsg_TypeRefinement), intent(in) :: criteria integer(C_INT), intent(in) :: output type(SwigClassWrapper) :: farg1 real(C_DOUBLE) :: farg2 integer(C_INT) :: farg3 integer(C_INT) :: farg4 farg1 = self%swigdata farg2 = tolerance farg3 = criteria farg4 = output call swigc_TasmanianSparseGrid_setSurplusRefinement__SWIG_5(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_setSurplusRefinement__SWIG_6(self, tolerance, criteria) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), intent(in) :: tolerance integer(tsg_TypeRefinement), intent(in) :: criteria type(SwigClassWrapper) :: farg1 real(C_DOUBLE) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = tolerance farg3 = criteria call swigc_TasmanianSparseGrid_setSurplusRefinement__SWIG_6(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_clearRefinement(self) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self type(SwigClassWrapper) :: farg1 farg1 = self%swigdata call swigc_TasmanianSparseGrid_clearRefinement(farg1) end subroutine subroutine swigf_TasmanianSparseGrid_mergeRefinement(self) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self type(SwigClassWrapper) :: farg1 farg1 = self%swigdata call swigc_TasmanianSparseGrid_mergeRefinement(farg1) end subroutine subroutine swigf_TasmanianSparseGrid_getHierarchicalCoefficientsStatic(self, coeff) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: coeff type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(coeff) call swigc_TasmanianSparseGrid_getHierarchicalCoefficientsStatic(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_setHierarchicalCoefficients__SWIG_1(self, c) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: c type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(c) call swigc_TasmanianSparseGrid_setHierarchicalCoefficients__SWIG_1(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_evaluateHierarchicalFunctions__SWIG_2(self, x, num_x, y) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x integer(C_INT), intent(in) :: num_x real(C_DOUBLE), dimension(*), target :: y type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = c_loc(x) farg3 = num_x farg4 = c_loc(y) call swigc_TasmanianSparseGrid_evaluateHierarchicalFunctions__SWIG_2(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_integrateHierarchicalFu1JSVB3__SWIG_2(self, integrals) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: integrals type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(integrals) call swigc_TasmanianSparseGrid_integrateHierarchicalFu1JSVB3__SWIG_2(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_printStats__SWIG_1(self) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self type(SwigClassWrapper) :: farg1 farg1 = self%swigdata call swigc_TasmanianSparseGrid_printStats__SWIG_1(farg1) end subroutine subroutine swigf_TasmanianSparseGrid_enableAcceleration__SWIG_0(self, acc) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(tsg_TypeAcceleration), intent(in) :: acc type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 farg1 = self%swigdata farg2 = acc call swigc_TasmanianSparseGrid_enableAcceleration__SWIG_0(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_enableAcceleration__SWIG_1(self, acc, new_gpu_id) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(tsg_TypeAcceleration), intent(in) :: acc integer(C_INT), intent(in) :: new_gpu_id type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = acc farg3 = new_gpu_id call swigc_TasmanianSparseGrid_enableAcceleration__SWIG_1(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_favorSparseAcceleration(self, favor) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self logical, intent(in) :: favor type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 farg1 = self%swigdata call SWIGTM_fin_bool(favor, farg2) call swigc_TasmanianSparseGrid_favorSparseAcceleration(farg1, farg2) end subroutine function swigf_TasmanianSparseGrid_getAccelerationType(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(tsg_TypeAcceleration) :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getAccelerationType(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_isAccelerationAvailable(acc) & result(swig_result) use, intrinsic :: ISO_C_BINDING logical :: swig_result integer(tsg_TypeAcceleration), intent(in) :: acc integer(C_INT) :: fresult integer(C_INT) :: farg1 farg1 = acc fresult = swigc_TasmanianSparseGrid_isAccelerationAvailable(farg1) call SWIGTM_fout_bool(fresult, swig_result) end function subroutine swigf_TasmanianSparseGrid_setGPUID(self, new_gpu_id) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: new_gpu_id type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 farg1 = self%swigdata farg2 = new_gpu_id call swigc_TasmanianSparseGrid_setGPUID(farg1, farg2) end subroutine function swigf_TasmanianSparseGrid_getGPUID(self) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: self integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 farg1 = self%swigdata fresult = swigc_TasmanianSparseGrid_getGPUID(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getNumGPUs() & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result integer(C_INT) :: fresult fresult = swigc_TasmanianSparseGrid_getNumGPUs() swig_result = fresult end function function swigf_TasmanianSparseGrid_getGPUMemory(gpu) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result integer(C_INT), intent(in) :: gpu integer(C_INT) :: fresult integer(C_INT) :: farg1 farg1 = gpu fresult = swigc_TasmanianSparseGrid_getGPUMemory(farg1) swig_result = fresult end function function swigf_TasmanianSparseGrid_getGPUName(gpu) & result(swig_result) use, intrinsic :: ISO_C_BINDING character(len=:), allocatable :: swig_result integer(C_INT), intent(in) :: gpu type(SwigArrayWrapper) :: fresult integer(C_INT) :: farg1 farg1 = gpu fresult = swigc_TasmanianSparseGrid_getGPUName(farg1) call SWIGTM_fout_char_Sm_(fresult, swig_result) call SWIG_free(fresult%data) end function subroutine swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_0(self, tolerance, output, scale_correction) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), intent(in) :: tolerance integer(C_INT), intent(in) :: output real(C_DOUBLE), dimension(*), target :: scale_correction type(SwigClassWrapper) :: farg1 real(C_DOUBLE) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = tolerance farg3 = output farg4 = c_loc(scale_correction) call swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_0(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_1(self, tolerance, output) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), intent(in) :: tolerance integer(C_INT), intent(in) :: output type(SwigClassWrapper) :: farg1 real(C_DOUBLE) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = tolerance farg3 = output call swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_1(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_2(self, tolerance) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), intent(in) :: tolerance type(SwigClassWrapper) :: farg1 real(C_DOUBLE) :: farg2 farg1 = self%swigdata farg2 = tolerance call swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_2(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_3(self, num_new_points, output, scale_correction) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: num_new_points integer(C_INT), intent(in) :: output real(C_DOUBLE), dimension(*), target :: scale_correction type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = num_new_points farg3 = output farg4 = c_loc(scale_correction) call swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_3(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_4(self, num_new_points, output) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: num_new_points integer(C_INT), intent(in) :: output type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = num_new_points farg3 = output call swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_4(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_5(self, num_new_points) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), intent(in) :: num_new_points type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 farg1 = self%swigdata farg2 = num_new_points call swigc_TasmanianSparseGrid_removePointsByHierarchi1EK9TY__SWIG_5(farg1, farg2) end subroutine function swigf_TasmanianSparseGrid_evaluateSparseHierarchicalFunct1CQM1I(self, x, num_x) & result(swig_result) use, intrinsic :: ISO_C_BINDING integer(C_INT) :: swig_result class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x integer(C_INT), intent(in) :: num_x integer(C_INT) :: fresult type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 integer(C_INT) :: farg3 farg1 = self%swigdata farg2 = c_loc(x) farg3 = num_x fresult = swigc_TasmanianSparseGrid_evaluateSparseHierarchicalFunct1CQM1I(farg1, farg2, farg3) swig_result = fresult end function subroutine swigf_TasmanianSparseGrid_evaluateSparseHierarchicalFunct1HRJEE(self, x, num_x, pntr, indx, vals) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x integer(C_INT), intent(in) :: num_x integer(C_INT), dimension(*), target :: pntr integer(C_INT), dimension(*), target :: indx real(C_DOUBLE), dimension(*), target :: vals type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 type(C_PTR) :: farg5 type(C_PTR) :: farg6 farg1 = self%swigdata farg2 = c_loc(x) farg3 = num_x farg4 = c_loc(pntr) farg5 = c_loc(indx) farg6 = c_loc(vals) call swigc_TasmanianSparseGrid_evaluateSparseHierarchicalFunct1HRJEE(farg1, farg2, farg3, farg4, farg5, farg6) end subroutine subroutine swigf_TasmanianSparseGrid_evaluateFast__SWIG_0(self, x, y) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: x real(C_DOUBLE), dimension(*), target :: y type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 type(C_PTR) :: farg3 farg1 = self%swigdata farg2 = c_loc(x) farg3 = c_loc(y) call swigc_TasmanianSparseGrid_evaluateFast__SWIG_0(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_evaluateFast__SWIG_2(self, x, y) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_FLOAT), dimension(*), target :: x real(C_FLOAT), dimension(*), target :: y type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 type(C_PTR) :: farg3 farg1 = self%swigdata farg2 = c_loc(x) farg3 = c_loc(y) call swigc_TasmanianSparseGrid_evaluateFast__SWIG_2(farg1, farg2, farg3) end subroutine subroutine swigf_TasmanianSparseGrid_evaluateBatchGPU__SWIG_0(self, gpu_x, cpu_num_x, gpu_y) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_DOUBLE), dimension(*), target :: gpu_x integer(C_INT), intent(in) :: cpu_num_x real(C_DOUBLE), dimension(*), target :: gpu_y type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = c_loc(gpu_x) farg3 = cpu_num_x farg4 = c_loc(gpu_y) call swigc_TasmanianSparseGrid_evaluateBatchGPU__SWIG_0(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_evaluateBatchGPU__SWIG_1(self, gpu_x, cpu_num_x, gpu_y) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self real(C_FLOAT), dimension(*), target :: gpu_x integer(C_INT), intent(in) :: cpu_num_x real(C_FLOAT), dimension(*), target :: gpu_y type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 integer(C_INT) :: farg3 type(C_PTR) :: farg4 farg1 = self%swigdata farg2 = c_loc(gpu_x) farg3 = cpu_num_x farg4 = c_loc(gpu_y) call swigc_TasmanianSparseGrid_evaluateBatchGPU__SWIG_1(farg1, farg2, farg3, farg4) end subroutine subroutine swigf_TasmanianSparseGrid_setConformalTransformASIN__SWIG_1(self, truncation) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(in) :: self integer(C_INT), dimension(*), target :: truncation type(SwigClassWrapper) :: farg1 type(C_PTR) :: farg2 farg1 = self%swigdata farg2 = c_loc(truncation) call swigc_TasmanianSparseGrid_setConformalTransformASIN__SWIG_1(farg1, farg2) end subroutine subroutine swigf_TasmanianSparseGrid_op_assign__(self, other) use, intrinsic :: ISO_C_BINDING class(TasmanianSparseGrid), intent(inout) :: self type(TasmanianSparseGrid), intent(in) :: other type(SwigClassWrapper) :: farg1 type(SwigClassWrapper) :: farg2 farg1 = self%swigdata farg2 = other%swigdata call swigc_TasmanianSparseGrid_op_assign__(farg1, farg2) self%swigdata = farg1 end subroutine function TasmanianReadGrid(filename) & result(swig_result) use, intrinsic :: ISO_C_BINDING type(TasmanianSparseGrid) :: swig_result character(len=*), intent(in) :: filename type(SwigClassWrapper) :: fresult character(kind=C_CHAR), dimension(:), allocatable, target :: farg1_temp type(SwigArrayWrapper) :: farg1 call SWIGTM_fin_char_Sm_(filename, farg1, farg1_temp) fresult = swigc_TasmanianReadGrid(farg1) swig_result%swigdata = fresult end function function swigf_TasmanianCopyGrid__SWIG_0(source, outputs_begin, outputs_end) & result(swig_result) use, intrinsic :: ISO_C_BINDING type(TasmanianSparseGrid) :: swig_result class(TasmanianSparseGrid), intent(in) :: source integer(C_INT), intent(in) :: outputs_begin integer(C_INT), intent(in) :: outputs_end type(SwigClassWrapper) :: fresult type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 integer(C_INT) :: farg3 farg1 = source%swigdata farg2 = outputs_begin farg3 = outputs_end fresult = swigc_TasmanianCopyGrid__SWIG_0(farg1, farg2, farg3) swig_result%swigdata = fresult end function function swigf_TasmanianCopyGrid__SWIG_1(source, outputs_begin) & result(swig_result) use, intrinsic :: ISO_C_BINDING type(TasmanianSparseGrid) :: swig_result class(TasmanianSparseGrid), intent(in) :: source integer(C_INT), intent(in) :: outputs_begin type(SwigClassWrapper) :: fresult type(SwigClassWrapper) :: farg1 integer(C_INT) :: farg2 farg1 = source%swigdata farg2 = outputs_begin fresult = swigc_TasmanianCopyGrid__SWIG_1(farg1, farg2) swig_result%swigdata = fresult end function function swigf_TasmanianCopyGrid__SWIG_2(source) & result(swig_result) use, intrinsic :: ISO_C_BINDING type(TasmanianSparseGrid) :: swig_result class(TasmanianSparseGrid), intent(in) :: source type(SwigClassWrapper) :: fresult type(SwigClassWrapper) :: farg1 farg1 = source%swigdata fresult = swigc_TasmanianCopyGrid__SWIG_2(farg1) swig_result%swigdata = fresult end function end module TASMANIAN-8.1/InterfaceSwig/generated/tasmanian_swigFORTRAN_wrap.cxx000066400000000000000000002655061470551176200252300ustar00rootroot00000000000000/* ---------------------------------------------------------------------------- * This file was automatically generated by SWIG (https://www.swig.org). * Version 4.2.0 * * Do not make changes to this file unless you know what you are doing - modify * the SWIG interface file instead. * ----------------------------------------------------------------------------- */ /* * TASMANIAN project, https://github.com/ORNL/TASMANIAN * Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. * Distributed under an MIT open source license: see LICENSE for details. */ /* ----------------------------------------------------------------------------- * This section contains generic SWIG labels for method/variable * declarations/attributes, and other compiler dependent labels. * ----------------------------------------------------------------------------- */ /* template workaround for compilers that cannot correctly implement the C++ standard */ #ifndef SWIGTEMPLATEDISAMBIGUATOR # if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) # define SWIGTEMPLATEDISAMBIGUATOR template # elif defined(__HP_aCC) /* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ /* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ # define SWIGTEMPLATEDISAMBIGUATOR template # else # define SWIGTEMPLATEDISAMBIGUATOR # endif #endif /* inline attribute */ #ifndef SWIGINLINE # if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) # define SWIGINLINE inline # else # define SWIGINLINE # endif #endif /* attribute recognised by some compilers to avoid 'unused' warnings */ #ifndef SWIGUNUSED # if defined(__GNUC__) # if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) # define SWIGUNUSED __attribute__ ((__unused__)) # else # define SWIGUNUSED # endif # elif defined(__ICC) # define SWIGUNUSED __attribute__ ((__unused__)) # else # define SWIGUNUSED # endif #endif #ifndef SWIG_MSC_UNSUPPRESS_4505 # if defined(_MSC_VER) # pragma warning(disable : 4505) /* unreferenced local function has been removed */ # endif #endif #ifndef SWIGUNUSEDPARM # ifdef __cplusplus # define SWIGUNUSEDPARM(p) # else # define SWIGUNUSEDPARM(p) p SWIGUNUSED # endif #endif /* internal SWIG method */ #ifndef SWIGINTERN # define SWIGINTERN static SWIGUNUSED #endif /* internal inline SWIG method */ #ifndef SWIGINTERNINLINE # define SWIGINTERNINLINE SWIGINTERN SWIGINLINE #endif /* exporting methods */ #if defined(__GNUC__) # if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) # ifndef GCC_HASCLASSVISIBILITY # define GCC_HASCLASSVISIBILITY # endif # endif #endif #ifndef SWIGEXPORT # if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) # if defined(STATIC_LINKED) # define SWIGEXPORT # else # define SWIGEXPORT __declspec(dllexport) # endif # else # if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) # define SWIGEXPORT __attribute__ ((visibility("default"))) # else # define SWIGEXPORT # endif # endif #endif /* calling conventions for Windows */ #ifndef SWIGSTDCALL # if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) # define SWIGSTDCALL __stdcall # else # define SWIGSTDCALL # endif #endif /* Deal with Microsoft's attempt at deprecating C standard runtime functions */ #if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) # define _CRT_SECURE_NO_DEPRECATE #endif /* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ #if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) # define _SCL_SECURE_NO_DEPRECATE #endif /* Deal with Apple's deprecated 'AssertMacros.h' from Carbon-framework */ #if defined(__APPLE__) && !defined(__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES) # define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 #endif /* Intel's compiler complains if a variable which was never initialised is * cast to void, which is a common idiom which we use to indicate that we * are aware a variable isn't used. So we just silence that warning. * See: https://github.com/swig/swig/issues/192 for more discussion. */ #ifdef __INTEL_COMPILER # pragma warning disable 592 #endif #if __cplusplus >=201103L # define SWIG_NULLPTR nullptr #else # define SWIG_NULLPTR NULL #endif /* C99 and C++11 should provide snprintf, but define SWIG_NO_SNPRINTF * if you're missing it. */ #if ((defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) || \ (defined __cplusplus && __cplusplus >= 201103L) || \ defined SWIG_HAVE_SNPRINTF) && \ !defined SWIG_NO_SNPRINTF # define SWIG_snprintf(O,S,F,A) snprintf(O,S,F,A) # define SWIG_snprintf2(O,S,F,A,B) snprintf(O,S,F,A,B) #else /* Fallback versions ignore the buffer size, but most of our uses either have a * fixed maximum possible size or dynamically allocate a buffer that's large * enough. */ # define SWIG_snprintf(O,S,F,A) sprintf(O,F,A) # define SWIG_snprintf2(O,S,F,A,B) sprintf(O,F,A,B) #endif #ifndef SWIGEXTERN # ifdef __cplusplus # define SWIGEXTERN extern # else # define SWIGEXTERN # endif #endif #define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ { throw std::logic_error("In " DECL ": " MSG); } /* SWIG Errors applicable to all language modules, values are reserved from -1 to -99 */ #define SWIG_UnknownError -1 #define SWIG_IOError -2 #define SWIG_RuntimeError -3 #define SWIG_IndexError -4 #define SWIG_TypeError -5 #define SWIG_DivisionByZero -6 #define SWIG_OverflowError -7 #define SWIG_SyntaxError -8 #define SWIG_ValueError -9 #define SWIG_SystemError -10 #define SWIG_AttributeError -11 #define SWIG_MemoryError -12 #define SWIG_NullReferenceError -13 #ifdef __cplusplus extern "C" { #endif SWIGEXPORT void SWIG_check_unhandled_exception_impl(const char* decl); SWIGEXPORT void SWIG_store_exception(const char* decl, int errcode, const char *msg); #ifdef __cplusplus } #endif #undef SWIG_exception_impl #define SWIG_exception_impl(DECL, CODE, MSG, RETURNNULL) \ SWIG_store_exception(DECL, CODE, MSG); RETURNNULL; enum SwigMemFlags { SWIG_MEM_OWN = 0x01, SWIG_MEM_RVALUE = 0x02, }; #define SWIG_check_nonnull(PTR, TYPENAME, FNAME, FUNCNAME, RETURNNULL) \ if (!(PTR)) { \ SWIG_exception_impl(FUNCNAME, SWIG_NullReferenceError, \ "Cannot pass null " TYPENAME " (class " FNAME ") " \ "as a reference", RETURNNULL); \ } namespace swig { enum AssignmentType { ASSIGNMENT_DEFAULT, ASSIGNMENT_NODESTRUCT, ASSIGNMENT_SMARTPTR }; } #define SWIG_VERSION 0x040200 #define SWIGFORTRAN #define SWIGPOLICY_TasGrid_TasmanianSparseGrid swig::ASSIGNMENT_DEFAULT #ifdef __cplusplus #include /* SwigValueWrapper is described in swig.swg */ template class SwigValueWrapper { struct SwigSmartPointer { T *ptr; SwigSmartPointer(T *p) : ptr(p) { } ~SwigSmartPointer() { delete ptr; } SwigSmartPointer& operator=(SwigSmartPointer& rhs) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = rhs.ptr; rhs.ptr = 0; return *this; } void reset(T *p) { T* oldptr = ptr; ptr = 0; delete oldptr; ptr = p; } } pointer; SwigValueWrapper& operator=(const SwigValueWrapper& rhs); SwigValueWrapper(const SwigValueWrapper& rhs); public: SwigValueWrapper() : pointer(0) { } SwigValueWrapper& operator=(const T& t) { SwigSmartPointer tmp(new T(t)); pointer = tmp; return *this; } #if __cplusplus >=201103L SwigValueWrapper& operator=(T&& t) { SwigSmartPointer tmp(new T(std::move(t))); pointer = tmp; return *this; } operator T&&() const { return std::move(*pointer.ptr); } #else operator T&() const { return *pointer.ptr; } #endif T *operator&() const { return pointer.ptr; } static void reset(SwigValueWrapper& t, T *p) { t.pointer.reset(p); } }; /* * SwigValueInit() is a generic initialisation solution as the following approach: * * T c_result = T(); * * doesn't compile for all types for example: * * unsigned int c_result = unsigned int(); */ template T SwigValueInit() { return T(); } #if __cplusplus >=201103L # define SWIG_STD_MOVE(OBJ) std::move(OBJ) #else # define SWIG_STD_MOVE(OBJ) OBJ #endif #endif #include /* Support for the `contract` feature. * * Note that RETURNNULL is first because it's inserted via a 'Replaceall' in * the fortran.cxx file. */ #define SWIG_contract_assert(RETURNNULL, EXPR, MSG) \ if (!(EXPR)) { SWIG_exception_impl("$decl", SWIG_ValueError, MSG, RETURNNULL); } #define SWIG_as_voidptr(a) const_cast< void * >(static_cast< const void * >(a)) #define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),reinterpret_cast< void** >(a)) extern "C" { int tasmanian_ierr = 0; } #include #ifdef _MSC_VER # ifndef strtoull # define strtoull _strtoui64 # endif # ifndef strtoll # define strtoll _strtoi64 # endif #endif struct SwigArrayWrapper { void* data; size_t size; }; SWIGINTERN SwigArrayWrapper SwigArrayWrapper_uninitialized() { SwigArrayWrapper result; result.data = NULL; result.size = 0; return result; } #include // Stored exception message SWIGINTERN const char* swig_last_exception_cstr = NULL; // Retrieve error message SWIGEXPORT const char* tasmanian_get_serr() { if (!swig_last_exception_cstr) { SWIG_store_exception("UNKNOWN", SWIG_RuntimeError, "no error string was present"); } return swig_last_exception_cstr; } #include #include extern "C" { // Call this function before any new action SWIGEXPORT void SWIG_check_unhandled_exception_impl(const char* decl) { if (tasmanian_ierr != 0) { // Construct message; calling the error string function ensures that // the string is allocated if the user did something goofy like // manually setting the integer. Since this function is not expected to // be wrapped by a catch statement, it will probably terminate the // program. std::string msg("An unhandled exception occurred before a call to "); msg += decl; msg += "; "; std::string prev_msg = tasmanian_get_serr(); prev_msg[0] = std::tolower(prev_msg[0]); msg += prev_msg; throw std::runtime_error(msg); } } // Save an exception to the fortran error code and string SWIGEXPORT void SWIG_store_exception(const char *decl, int errcode, const char *msg) { ::tasmanian_ierr = errcode; static std::string last_exception_msg; // Save the message to a std::string first last_exception_msg = "In "; last_exception_msg += decl; last_exception_msg += ": "; last_exception_msg += msg; swig_last_exception_cstr = last_exception_msg.c_str(); } } #include #include #include #include "tsgEnumerates.hpp" #include "TasmanianSparseGrid.hpp" struct SwigClassWrapper { void* cptr; int cmemflags; }; SWIGINTERN SwigClassWrapper SwigClassWrapper_uninitialized() { SwigClassWrapper result; result.cptr = NULL; result.cmemflags = 0; return result; } SWIGINTERN void TasGrid_TasmanianSparseGrid_setConformalTransformASIN__SWIG_1(TasGrid::TasmanianSparseGrid *self,int *truncation){ self->setConformalTransformASIN( std::vector(truncation, truncation + self->getNumDimensions()) ); } namespace swig { template struct DestructorPolicy { static SwigClassWrapper destroy(SwigClassWrapper self) { delete static_cast(self.cptr); return SwigClassWrapper_uninitialized(); } }; template struct DestructorPolicy { static SwigClassWrapper destroy(SwigClassWrapper) { SWIG_exception_impl("assignment", SWIG_TypeError, "Invalid assignment: class type has private destructor", return SwigClassWrapper_uninitialized()); } }; } namespace swig { SWIGINTERN SwigClassWrapper capture(SwigClassWrapper other) { other.cmemflags &= ~SWIG_MEM_RVALUE; return other; } template struct AssignmentPolicy { static SwigClassWrapper destroy(SwigClassWrapper self) { return DestructorPolicy::destroy(self); } static SwigClassWrapper alias(SwigClassWrapper other) { SwigClassWrapper self = other; self.cmemflags &= ~SWIG_MEM_OWN; return self; } static SwigClassWrapper move_alias(SwigClassWrapper self, SwigClassWrapper other) { if (self.cmemflags & SWIG_MEM_OWN) { destroy(self); } return capture(other); } static SwigClassWrapper copy_alias(SwigClassWrapper self, SwigClassWrapper other) { if (self.cmemflags & SWIG_MEM_OWN) { destroy(self); } return capture(other); } }; template struct AssignmentPolicy { static SwigClassWrapper destroy(SwigClassWrapper self) { return DestructorPolicy::destroy(self); } static SwigClassWrapper alias(SwigClassWrapper other) { SwigClassWrapper self; self.cptr = new T(*static_cast(other.cptr)); self.cmemflags = other.cmemflags | SWIG_MEM_OWN; return self; } static SwigClassWrapper move_alias(SwigClassWrapper self, SwigClassWrapper other) { self = copy_alias(self, other); self.cmemflags = other.cmemflags & ~SWIG_MEM_RVALUE; destroy(other); return self; } static SwigClassWrapper copy_alias(SwigClassWrapper self, SwigClassWrapper other) { // LHS and RHS should both 'own' their shared pointers T *pself = static_cast(self.cptr); T *pother = static_cast(other.cptr); *pself = *pother; return self; } }; } // end namespace swig template SWIGINTERN void SWIG_assign(SwigClassWrapper* self, SwigClassWrapper other) { typedef swig::AssignmentPolicy Policy_t; if (self->cptr == NULL) { /* LHS is unassigned */ if (other.cmemflags & SWIG_MEM_RVALUE) { /* Capture pointer from RHS, clear 'moving' flag */ *self = swig::capture(other); } else { /* Aliasing another class; clear ownership or copy smart pointer */ *self = Policy_t::alias(other); } } else if (other.cptr == NULL) { /* Replace LHS with a null pointer */ *self = Policy_t::destroy(*self); } else if (self->cptr == other.cptr) { /* Self-assignment: ignore */ } else if (other.cmemflags & SWIG_MEM_RVALUE) { /* Transferred ownership from a variable that's about to be lost. * Move-assign and delete the transient data */ *self = Policy_t::move_alias(*self, other); } else { /* RHS shouldn't be deleted, alias to LHS */ *self = Policy_t::copy_alias(*self, other); } } template SWIGINTERN void SWIG_free_rvalue(SwigClassWrapper other) { typedef swig::AssignmentPolicy Policy_t; if (other.cmemflags & SWIG_MEM_RVALUE && other.cmemflags & SWIG_MEM_OWN) { /* We own *and* are being passed an expiring value */ Policy_t::destroy(other); } } extern "C" { SWIGEXPORT SwigArrayWrapper _wrap_get_serr() { SwigArrayWrapper fresult ; char *result = 0 ; result = (char *)tasmanian_get_serr(); fresult.size = strlen((char*)(result)); fresult.data = const_cast< char * >(result); return fresult; } SWIGEXPORT SwigClassWrapper _wrap_new_TasmanianSparseGrid__SWIG_0() { SwigClassWrapper fresult ; TasGrid::TasmanianSparseGrid *result = 0 ; result = (TasGrid::TasmanianSparseGrid *)new TasGrid::TasmanianSparseGrid(); fresult.cptr = (void*)result; fresult.cmemflags = SWIG_MEM_RVALUE | (1 ? SWIG_MEM_OWN : 0); return fresult; } SWIGEXPORT SwigClassWrapper _wrap_new_TasmanianSparseGrid__SWIG_1(SwigClassWrapper *farg1) { SwigClassWrapper fresult ; TasGrid::TasmanianSparseGrid *arg1 = 0 ; TasGrid::TasmanianSparseGrid *result = 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const &", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::TasmanianSparseGrid(TasGrid::TasmanianSparseGrid const &)", return SwigClassWrapper_uninitialized()); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (TasGrid::TasmanianSparseGrid *)new TasGrid::TasmanianSparseGrid((TasGrid::TasmanianSparseGrid const &)*arg1); fresult.cptr = (void*)result; fresult.cmemflags = SWIG_MEM_RVALUE | (1 ? SWIG_MEM_OWN : 0); return fresult; } SWIGEXPORT void _wrap_delete_TasmanianSparseGrid(SwigClassWrapper *farg1) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; delete arg1; } SWIGEXPORT SwigArrayWrapper _wrap_TasmanianSparseGrid_getVersion() { SwigArrayWrapper fresult ; char *result = 0 ; result = (char *)TasGrid::TasmanianSparseGrid::getVersion(); fresult.size = strlen((char*)(result)); fresult.data = const_cast< char * >(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getVersionMajor() { int fresult ; int result; result = (int)TasGrid::TasmanianSparseGrid::getVersionMajor(); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getVersionMinor() { int fresult ; int result; result = (int)TasGrid::TasmanianSparseGrid::getVersionMinor(); fresult = (int)(result); return fresult; } SWIGEXPORT SwigArrayWrapper _wrap_TasmanianSparseGrid_getLicense() { SwigArrayWrapper fresult ; char *result = 0 ; result = (char *)TasGrid::TasmanianSparseGrid::getLicense(); fresult.size = strlen((char*)(result)); fresult.data = const_cast< char * >(result); return fresult; } SWIGEXPORT SwigArrayWrapper _wrap_TasmanianSparseGrid_getGitCommitHash() { SwigArrayWrapper fresult ; char *result = 0 ; result = (char *)TasGrid::TasmanianSparseGrid::getGitCommitHash(); fresult.size = strlen((char*)(result)); fresult.data = const_cast< char * >(result); return fresult; } SWIGEXPORT SwigArrayWrapper _wrap_TasmanianSparseGrid_getCmakeCxxFlags() { SwigArrayWrapper fresult ; char *result = 0 ; result = (char *)TasGrid::TasmanianSparseGrid::getCmakeCxxFlags(); fresult.size = strlen((char*)(result)); fresult.data = const_cast< char * >(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isOpenMPEnabled() { int fresult ; bool result; result = (bool)TasGrid::TasmanianSparseGrid::isOpenMPEnabled(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isCudaEnabled() { int fresult ; bool result; result = (bool)TasGrid::TasmanianSparseGrid::isCudaEnabled(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isHipEnabled() { int fresult ; bool result; result = (bool)TasGrid::TasmanianSparseGrid::isHipEnabled(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isDpcppEnabled() { int fresult ; bool result; result = (bool)TasGrid::TasmanianSparseGrid::isDpcppEnabled(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT void _wrap_TasmanianSparseGrid_write__SWIG_0(SwigClassWrapper *farg1, SwigArrayWrapper *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; char *arg2 = (char *) 0 ; bool arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::write(char const *,bool) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (char *)(farg2->data); arg3 = (*farg3 ? true : false); ((TasGrid::TasmanianSparseGrid const *)arg1)->write((char const *)arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_write__SWIG_1(SwigClassWrapper *farg1, SwigArrayWrapper *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; char *arg2 = (char *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::write(char const *) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (char *)(farg2->data); ((TasGrid::TasmanianSparseGrid const *)arg1)->write((char const *)arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_read__SWIG_0(SwigClassWrapper *farg1, SwigArrayWrapper *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; char *arg2 = (char *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::read(char const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (char *)(farg2->data); (arg1)->read((char const *)arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_5(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6, int *farg7, double const *farg8, double const *farg9, SwigArrayWrapper *farg10, int *farg11) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; TasGrid::TypeOneDRule arg6 ; int *arg7 = (int *) 0 ; double arg8 ; double arg9 ; char *arg10 = (char *) 0 ; int *arg11 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeGlobalGrid(int,int,int,TasGrid::TypeDepth,TasGrid::TypeOneDRule,int const *,double,double,char const *,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); arg7 = (int *)(farg7); arg8 = (double)(*farg8); arg9 = (double)(*farg9); arg10 = (char *)(farg10->data); arg11 = (int *)(farg11); (arg1)->makeGlobalGrid(arg2,arg3,arg4,arg5,arg6,(int const *)arg7,arg8,arg9,(char const *)arg10,(int const *)arg11); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_6(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6, int *farg7, double const *farg8, double const *farg9, SwigArrayWrapper *farg10) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; TasGrid::TypeOneDRule arg6 ; int *arg7 = (int *) 0 ; double arg8 ; double arg9 ; char *arg10 = (char *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeGlobalGrid(int,int,int,TasGrid::TypeDepth,TasGrid::TypeOneDRule,int const *,double,double,char const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); arg7 = (int *)(farg7); arg8 = (double)(*farg8); arg9 = (double)(*farg9); arg10 = (char *)(farg10->data); (arg1)->makeGlobalGrid(arg2,arg3,arg4,arg5,arg6,(int const *)arg7,arg8,arg9,(char const *)arg10); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_7(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6, int *farg7, double const *farg8, double const *farg9) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; TasGrid::TypeOneDRule arg6 ; int *arg7 = (int *) 0 ; double arg8 ; double arg9 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeGlobalGrid(int,int,int,TasGrid::TypeDepth,TasGrid::TypeOneDRule,int const *,double,double)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); arg7 = (int *)(farg7); arg8 = (double)(*farg8); arg9 = (double)(*farg9); (arg1)->makeGlobalGrid(arg2,arg3,arg4,arg5,arg6,(int const *)arg7,arg8,arg9); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_8(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6, int *farg7, double const *farg8) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; TasGrid::TypeOneDRule arg6 ; int *arg7 = (int *) 0 ; double arg8 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeGlobalGrid(int,int,int,TasGrid::TypeDepth,TasGrid::TypeOneDRule,int const *,double)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); arg7 = (int *)(farg7); arg8 = (double)(*farg8); (arg1)->makeGlobalGrid(arg2,arg3,arg4,arg5,arg6,(int const *)arg7,arg8); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_9(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6, int *farg7) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; TasGrid::TypeOneDRule arg6 ; int *arg7 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeGlobalGrid(int,int,int,TasGrid::TypeDepth,TasGrid::TypeOneDRule,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); arg7 = (int *)(farg7); (arg1)->makeGlobalGrid(arg2,arg3,arg4,arg5,arg6,(int const *)arg7); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeGlobalGrid__SWIG_10(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; TasGrid::TypeOneDRule arg6 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeGlobalGrid(int,int,int,TasGrid::TypeDepth,TasGrid::TypeOneDRule)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); (arg1)->makeGlobalGrid(arg2,arg3,arg4,arg5,arg6); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeSequenceGrid__SWIG_2(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6, int *farg7, int *farg8) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; TasGrid::TypeOneDRule arg6 ; int *arg7 = (int *) 0 ; int *arg8 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeSequenceGrid(int,int,int,TasGrid::TypeDepth,TasGrid::TypeOneDRule,int const *,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); arg7 = (int *)(farg7); arg8 = (int *)(farg8); (arg1)->makeSequenceGrid(arg2,arg3,arg4,arg5,arg6,(int const *)arg7,(int const *)arg8); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeSequenceGrid__SWIG_3(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6, int *farg7) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; TasGrid::TypeOneDRule arg6 ; int *arg7 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeSequenceGrid(int,int,int,TasGrid::TypeDepth,TasGrid::TypeOneDRule,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); arg7 = (int *)(farg7); (arg1)->makeSequenceGrid(arg2,arg3,arg4,arg5,arg6,(int const *)arg7); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeSequenceGrid__SWIG_4(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; TasGrid::TypeOneDRule arg6 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeSequenceGrid(int,int,int,TasGrid::TypeDepth,TasGrid::TypeOneDRule)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); (arg1)->makeSequenceGrid(arg2,arg3,arg4,arg5,arg6); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_1(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6, int *farg7) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; int arg5 ; TasGrid::TypeOneDRule arg6 ; int *arg7 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeLocalPolynomialGrid(int,int,int,int,TasGrid::TypeOneDRule,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (int)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); arg7 = (int *)(farg7); (arg1)->makeLocalPolynomialGrid(arg2,arg3,arg4,arg5,arg6,(int const *)arg7); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_2(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int const *farg6) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; int arg5 ; TasGrid::TypeOneDRule arg6 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeLocalPolynomialGrid(int,int,int,int,TasGrid::TypeOneDRule)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (int)(*farg5); arg6 = (TasGrid::TypeOneDRule)(*farg6); (arg1)->makeLocalPolynomialGrid(arg2,arg3,arg4,arg5,arg6); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_3(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; int arg5 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeLocalPolynomialGrid(int,int,int,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (int)(*farg5); (arg1)->makeLocalPolynomialGrid(arg2,arg3,arg4,arg5); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeLocalPolynomialGrid__SWIG_4(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeLocalPolynomialGrid(int,int,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); (arg1)->makeLocalPolynomialGrid(arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeWaveletGrid__SWIG_1(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int *farg6) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; int arg5 ; int *arg6 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeWaveletGrid(int,int,int,int,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (int)(*farg5); arg6 = (int *)(farg6); (arg1)->makeWaveletGrid(arg2,arg3,arg4,arg5,(int const *)arg6); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeWaveletGrid__SWIG_2(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; int arg5 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeWaveletGrid(int,int,int,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (int)(*farg5); (arg1)->makeWaveletGrid(arg2,arg3,arg4,arg5); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeWaveletGrid__SWIG_3(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeWaveletGrid(int,int,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); (arg1)->makeWaveletGrid(arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeFourierGrid__SWIG_2(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int *farg6, int *farg7) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; int *arg6 = (int *) 0 ; int *arg7 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeFourierGrid(int,int,int,TasGrid::TypeDepth,int const *,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (int *)(farg6); arg7 = (int *)(farg7); (arg1)->makeFourierGrid(arg2,arg3,arg4,arg5,(int const *)arg6,(int const *)arg7); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeFourierGrid__SWIG_3(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5, int *farg6) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; int *arg6 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeFourierGrid(int,int,int,TasGrid::TypeDepth,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); arg6 = (int *)(farg6); (arg1)->makeFourierGrid(arg2,arg3,arg4,arg5,(int const *)arg6); } SWIGEXPORT void _wrap_TasmanianSparseGrid_makeFourierGrid__SWIG_4(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int const *farg5) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; int arg4 ; TasGrid::TypeDepth arg5 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::makeFourierGrid(int,int,int,TasGrid::TypeDepth)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (TasGrid::TypeDepth)(*farg5); (arg1)->makeFourierGrid(arg2,arg3,arg4,arg5); } SWIGEXPORT void _wrap_TasmanianSparseGrid_copyGrid__SWIG_0(SwigClassWrapper *farg1, SwigClassWrapper *farg2, int const *farg3, int const *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TasmanianSparseGrid *arg2 = 0 ; int arg3 ; int arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::copyGrid(TasGrid::TasmanianSparseGrid const &,int,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; SWIG_check_nonnull(farg2->cptr, "TasGrid::TasmanianSparseGrid const &", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::copyGrid(TasGrid::TasmanianSparseGrid const &,int,int)", return ); arg2 = (TasGrid::TasmanianSparseGrid *)farg2->cptr; arg3 = (int)(*farg3); arg4 = (int)(*farg4); (arg1)->copyGrid((TasGrid::TasmanianSparseGrid const &)*arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_copyGrid__SWIG_1(SwigClassWrapper *farg1, SwigClassWrapper *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TasmanianSparseGrid *arg2 = 0 ; int arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::copyGrid(TasGrid::TasmanianSparseGrid const &,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; SWIG_check_nonnull(farg2->cptr, "TasGrid::TasmanianSparseGrid const &", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::copyGrid(TasGrid::TasmanianSparseGrid const &,int)", return ); arg2 = (TasGrid::TasmanianSparseGrid *)farg2->cptr; arg3 = (int)(*farg3); (arg1)->copyGrid((TasGrid::TasmanianSparseGrid const &)*arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_copyGrid__SWIG_2(SwigClassWrapper *farg1, SwigClassWrapper *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TasmanianSparseGrid *arg2 = 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::copyGrid(TasGrid::TasmanianSparseGrid const &)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; SWIG_check_nonnull(farg2->cptr, "TasGrid::TasmanianSparseGrid const &", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::copyGrid(TasGrid::TasmanianSparseGrid const &)", return ); arg2 = (TasGrid::TasmanianSparseGrid *)farg2->cptr; (arg1)->copyGrid((TasGrid::TasmanianSparseGrid const &)*arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateGlobalGrid__SWIG_2(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int *farg4, int *farg5) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; int *arg4 = (int *) 0 ; int *arg5 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateGlobalGrid(int,TasGrid::TypeDepth,int const *,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); arg4 = (int *)(farg4); arg5 = (int *)(farg5); (arg1)->updateGlobalGrid(arg2,arg3,(int const *)arg4,(int const *)arg5); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateGlobalGrid__SWIG_3(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; int *arg4 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateGlobalGrid(int,TasGrid::TypeDepth,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); arg4 = (int *)(farg4); (arg1)->updateGlobalGrid(arg2,arg3,(int const *)arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateGlobalGrid__SWIG_4(SwigClassWrapper *farg1, int const *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateGlobalGrid(int,TasGrid::TypeDepth)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); (arg1)->updateGlobalGrid(arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateSequenceGrid__SWIG_2(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int *farg4, int *farg5) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; int *arg4 = (int *) 0 ; int *arg5 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateSequenceGrid(int,TasGrid::TypeDepth,int const *,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); arg4 = (int *)(farg4); arg5 = (int *)(farg5); (arg1)->updateSequenceGrid(arg2,arg3,(int const *)arg4,(int const *)arg5); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateSequenceGrid__SWIG_3(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; int *arg4 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateSequenceGrid(int,TasGrid::TypeDepth,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); arg4 = (int *)(farg4); (arg1)->updateSequenceGrid(arg2,arg3,(int const *)arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateSequenceGrid__SWIG_4(SwigClassWrapper *farg1, int const *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateSequenceGrid(int,TasGrid::TypeDepth)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); (arg1)->updateSequenceGrid(arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateFourierGrid__SWIG_2(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int *farg4, int *farg5) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; int *arg4 = (int *) 0 ; int *arg5 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateFourierGrid(int,TasGrid::TypeDepth,int const *,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); arg4 = (int *)(farg4); arg5 = (int *)(farg5); (arg1)->updateFourierGrid(arg2,arg3,(int const *)arg4,(int const *)arg5); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateFourierGrid__SWIG_3(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; int *arg4 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateFourierGrid(int,TasGrid::TypeDepth,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); arg4 = (int *)(farg4); (arg1)->updateFourierGrid(arg2,arg3,(int const *)arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateFourierGrid__SWIG_4(SwigClassWrapper *farg1, int const *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateFourierGrid(int,TasGrid::TypeDepth)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); (arg1)->updateFourierGrid(arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateGrid__SWIG_2(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int *farg4, int *farg5) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; int *arg4 = (int *) 0 ; int *arg5 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateGrid(int,TasGrid::TypeDepth,int const *,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); arg4 = (int *)(farg4); arg5 = (int *)(farg5); (arg1)->updateGrid(arg2,arg3,(int const *)arg4,(int const *)arg5); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateGrid__SWIG_3(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; int *arg4 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateGrid(int,TasGrid::TypeDepth,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); arg4 = (int *)(farg4); (arg1)->updateGrid(arg2,arg3,(int const *)arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_updateGrid__SWIG_4(SwigClassWrapper *farg1, int const *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; TasGrid::TypeDepth arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::updateGrid(int,TasGrid::TypeDepth)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (TasGrid::TypeDepth)(*farg3); (arg1)->updateGrid(arg2,arg3); } SWIGEXPORT double _wrap_TasmanianSparseGrid_getAlpha(SwigClassWrapper *farg1) { double fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getAlpha() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (double)((TasGrid::TasmanianSparseGrid const *)arg1)->getAlpha(); fresult = (double)(result); return fresult; } SWIGEXPORT double _wrap_TasmanianSparseGrid_getBeta(SwigClassWrapper *farg1) { double fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getBeta() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (double)((TasGrid::TasmanianSparseGrid const *)arg1)->getBeta(); fresult = (double)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getOrder(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getOrder() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (int)((TasGrid::TasmanianSparseGrid const *)arg1)->getOrder(); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getNumDimensions(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getNumDimensions() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (int)((TasGrid::TasmanianSparseGrid const *)arg1)->getNumDimensions(); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getNumOutputs(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getNumOutputs() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (int)((TasGrid::TasmanianSparseGrid const *)arg1)->getNumOutputs(); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getRule(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TypeOneDRule result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getRule() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (TasGrid::TypeOneDRule)((TasGrid::TasmanianSparseGrid const *)arg1)->getRule(); fresult = (int)(result); return fresult; } SWIGEXPORT SwigArrayWrapper _wrap_TasmanianSparseGrid_getCustomRuleDescription(SwigClassWrapper *farg1) { SwigArrayWrapper fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; char *result = 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getCustomRuleDescription() const", return SwigArrayWrapper_uninitialized()); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (char *)((TasGrid::TasmanianSparseGrid const *)arg1)->getCustomRuleDescription(); fresult.size = strlen((char*)(result)); fresult.data = const_cast< char * >(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getNumLoaded(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getNumLoaded() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (int)((TasGrid::TasmanianSparseGrid const *)arg1)->getNumLoaded(); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getNumNeeded(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getNumNeeded() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (int)((TasGrid::TasmanianSparseGrid const *)arg1)->getNumNeeded(); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getNumPoints(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getNumPoints() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (int)((TasGrid::TasmanianSparseGrid const *)arg1)->getNumPoints(); fresult = (int)(result); return fresult; } SWIGEXPORT void _wrap_TasmanianSparseGrid_getLoadedPoints__SWIG_2(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getLoadedPoints(double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); ((TasGrid::TasmanianSparseGrid const *)arg1)->getLoadedPoints(arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_getNeededPoints__SWIG_2(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 = (double *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getNeededPoints(double *) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); ((TasGrid::TasmanianSparseGrid const *)arg1)->getNeededPoints(arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_getPoints__SWIG_2(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getPoints(double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); ((TasGrid::TasmanianSparseGrid const *)arg1)->getPoints(arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_getQuadratureWeights__SWIG_2(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getQuadratureWeights(double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); ((TasGrid::TasmanianSparseGrid const *)arg1)->getQuadratureWeights(arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_getInterpolationWeights__SWIG_3(SwigClassWrapper *farg1, double *farg2, double *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; double *arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getInterpolationWeights(double const [],double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (double *)(farg3); ((TasGrid::TasmanianSparseGrid const *)arg1)->getInterpolationWeights((double const (*))arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_getDifferentiationWeights__SWIG_3(SwigClassWrapper *farg1, double *farg2, double *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; double *arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getDifferentiationWeights(double const [],double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (double *)(farg3); ((TasGrid::TasmanianSparseGrid const *)arg1)->getDifferentiationWeights((double const (*))arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_loadNeededValues__SWIG_1(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 = (double *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::loadNeededValues(double const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); (arg1)->loadNeededValues((double const *)arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_loadNeededPoints__SWIG_1(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 = (double *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::loadNeededPoints(double const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); (arg1)->loadNeededPoints((double const *)arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_evaluate__SWIG_1(SwigClassWrapper *farg1, double *farg2, double *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; double *arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluate(double const [],double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (double *)(farg3); ((TasGrid::TasmanianSparseGrid const *)arg1)->evaluate((double const (*))arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_evaluateBatch__SWIG_0(SwigClassWrapper *farg1, double *farg2, int const *farg3, double *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; int arg3 ; double *arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluateBatch(double const [],int,double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (int)(*farg3); arg4 = (double *)(farg4); ((TasGrid::TasmanianSparseGrid const *)arg1)->evaluateBatch((double const (*))arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_evaluateBatch__SWIG_1(SwigClassWrapper *farg1, float *farg2, int const *farg3, float *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; float *arg2 ; int arg3 ; float *arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluateBatch(float const [],int,float []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (float *)(farg2); arg3 = (int)(*farg3); arg4 = (float *)(farg4); ((TasGrid::TasmanianSparseGrid const *)arg1)->evaluateBatch((float const (*))arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_integrate__SWIG_1(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::integrate(double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); ((TasGrid::TasmanianSparseGrid const *)arg1)->integrate(arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_differentiate__SWIG_2(SwigClassWrapper *farg1, double *farg2, double *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; double *arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::differentiate(double const [],double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (double *)(farg3); ((TasGrid::TasmanianSparseGrid const *)arg1)->differentiate((double const (*))arg2,arg3); } SWIGEXPORT int _wrap_TasmanianSparseGrid_isGlobal(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::isGlobal() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (bool)((TasGrid::TasmanianSparseGrid const *)arg1)->isGlobal(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isSequence(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::isSequence() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (bool)((TasGrid::TasmanianSparseGrid const *)arg1)->isSequence(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isLocalPolynomial(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::isLocalPolynomial() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (bool)((TasGrid::TasmanianSparseGrid const *)arg1)->isLocalPolynomial(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isWavelet(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::isWavelet() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (bool)((TasGrid::TasmanianSparseGrid const *)arg1)->isWavelet(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isFourier(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::isFourier() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (bool)((TasGrid::TasmanianSparseGrid const *)arg1)->isFourier(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isEmpty(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::isEmpty() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (bool)((TasGrid::TasmanianSparseGrid const *)arg1)->isEmpty(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_empty(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::empty() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (bool)((TasGrid::TasmanianSparseGrid const *)arg1)->empty(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT void _wrap_TasmanianSparseGrid_setDomainTransform__SWIG_1(SwigClassWrapper *farg1, double *farg2, double *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; double *arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setDomainTransform(double const [],double const [])", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (double *)(farg3); (arg1)->setDomainTransform((double const (*))arg2,(double const (*))arg3); } SWIGEXPORT int _wrap_TasmanianSparseGrid_isSetDomainTransfrom(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::isSetDomainTransfrom() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (bool)((TasGrid::TasmanianSparseGrid const *)arg1)->isSetDomainTransfrom(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT void _wrap_TasmanianSparseGrid_clearDomainTransform(SwigClassWrapper *farg1) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::clearDomainTransform()", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; (arg1)->clearDomainTransform(); } SWIGEXPORT void _wrap_TasmanianSparseGrid_getDomainTransform__SWIG_1(SwigClassWrapper *farg1, double *farg2, double *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; double *arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getDomainTransform(double [],double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (double *)(farg3); ((TasGrid::TasmanianSparseGrid const *)arg1)->getDomainTransform(arg2,arg3); } SWIGEXPORT int _wrap_TasmanianSparseGrid_isSetConformalTransformASIN(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::isSetConformalTransformASIN() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (bool)((TasGrid::TasmanianSparseGrid const *)arg1)->isSetConformalTransformASIN(); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT void _wrap_TasmanianSparseGrid_clearConformalTransform(SwigClassWrapper *farg1) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::clearConformalTransform()", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; (arg1)->clearConformalTransform(); } SWIGEXPORT void _wrap_TasmanianSparseGrid_clearLevelLimits(SwigClassWrapper *farg1) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::clearLevelLimits()", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; (arg1)->clearLevelLimits(); } SWIGEXPORT void _wrap_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_1(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4, int *farg5) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TypeDepth arg2 ; int arg3 ; int arg4 ; int *arg5 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setAnisotropicRefinement(TasGrid::TypeDepth,int,int,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (TasGrid::TypeDepth)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); arg5 = (int *)(farg5); (arg1)->setAnisotropicRefinement(arg2,arg3,arg4,(int const *)arg5); } SWIGEXPORT void _wrap_TasmanianSparseGrid_setAnisotropicRefinement__SWIG_2(SwigClassWrapper *farg1, int const *farg2, int const *farg3, int const *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TypeDepth arg2 ; int arg3 ; int arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setAnisotropicRefinement(TasGrid::TypeDepth,int,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (TasGrid::TypeDepth)(*farg2); arg3 = (int)(*farg3); arg4 = (int)(*farg4); (arg1)->setAnisotropicRefinement(arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_setSurplusRefinement__SWIG_3(SwigClassWrapper *farg1, double const *farg2, int const *farg3, int const *farg4, int *farg5, double *farg6) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double arg2 ; TasGrid::TypeRefinement arg3 ; int arg4 ; int *arg5 = (int *) 0 ; double *arg6 = (double *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setSurplusRefinement(double,TasGrid::TypeRefinement,int,int const *,double const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double)(*farg2); arg3 = (TasGrid::TypeRefinement)(*farg3); arg4 = (int)(*farg4); arg5 = (int *)(farg5); arg6 = (double *)(farg6); (arg1)->setSurplusRefinement(arg2,arg3,arg4,(int const *)arg5,(double const *)arg6); } SWIGEXPORT void _wrap_TasmanianSparseGrid_setSurplusRefinement__SWIG_4(SwigClassWrapper *farg1, double const *farg2, int const *farg3, int const *farg4, int *farg5) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double arg2 ; TasGrid::TypeRefinement arg3 ; int arg4 ; int *arg5 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setSurplusRefinement(double,TasGrid::TypeRefinement,int,int const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double)(*farg2); arg3 = (TasGrid::TypeRefinement)(*farg3); arg4 = (int)(*farg4); arg5 = (int *)(farg5); (arg1)->setSurplusRefinement(arg2,arg3,arg4,(int const *)arg5); } SWIGEXPORT void _wrap_TasmanianSparseGrid_setSurplusRefinement__SWIG_5(SwigClassWrapper *farg1, double const *farg2, int const *farg3, int const *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double arg2 ; TasGrid::TypeRefinement arg3 ; int arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setSurplusRefinement(double,TasGrid::TypeRefinement,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double)(*farg2); arg3 = (TasGrid::TypeRefinement)(*farg3); arg4 = (int)(*farg4); (arg1)->setSurplusRefinement(arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_setSurplusRefinement__SWIG_6(SwigClassWrapper *farg1, double const *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double arg2 ; TasGrid::TypeRefinement arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setSurplusRefinement(double,TasGrid::TypeRefinement)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double)(*farg2); arg3 = (TasGrid::TypeRefinement)(*farg3); (arg1)->setSurplusRefinement(arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_clearRefinement(SwigClassWrapper *farg1) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::clearRefinement()", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; (arg1)->clearRefinement(); } SWIGEXPORT void _wrap_TasmanianSparseGrid_mergeRefinement(SwigClassWrapper *farg1) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::mergeRefinement()", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; (arg1)->mergeRefinement(); } SWIGEXPORT void _wrap_TasmanianSparseGrid_getHierarchicalCoefficientsStatic(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 = (double *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getHierarchicalCoefficientsStatic(double *) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); ((TasGrid::TasmanianSparseGrid const *)arg1)->getHierarchicalCoefficientsStatic(arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_setHierarchicalCoefficients__SWIG_1(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setHierarchicalCoefficients(double const [])", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); (arg1)->setHierarchicalCoefficients((double const (*))arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_evaluateHierarchicalFunctions__SWIG_2(SwigClassWrapper *farg1, double *farg2, int const *farg3, double *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; int arg3 ; double *arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluateHierarchicalFunctions(double const [],int,double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (int)(*farg3); arg4 = (double *)(farg4); ((TasGrid::TasmanianSparseGrid const *)arg1)->evaluateHierarchicalFunctions((double const (*))arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_integrateHierarchicalFunctions__SWIG_2(SwigClassWrapper *farg1, double *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::integrateHierarchicalFunctions(double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); ((TasGrid::TasmanianSparseGrid const *)arg1)->integrateHierarchicalFunctions(arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_printStats__SWIG_1(SwigClassWrapper *farg1) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::printStats() const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; ((TasGrid::TasmanianSparseGrid const *)arg1)->printStats(); } SWIGEXPORT void _wrap_TasmanianSparseGrid_enableAcceleration__SWIG_0(SwigClassWrapper *farg1, int const *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TypeAcceleration arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::enableAcceleration(TasGrid::TypeAcceleration)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (TasGrid::TypeAcceleration)(*farg2); (arg1)->enableAcceleration(arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_enableAcceleration__SWIG_1(SwigClassWrapper *farg1, int const *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TypeAcceleration arg2 ; int arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::enableAcceleration(TasGrid::TypeAcceleration,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (TasGrid::TypeAcceleration)(*farg2); arg3 = (int)(*farg3); (arg1)->enableAcceleration(arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_favorSparseAcceleration(SwigClassWrapper *farg1, int const *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; bool arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::favorSparseAcceleration(bool)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (*farg2 ? true : false); (arg1)->favorSparseAcceleration(arg2); } SWIGEXPORT int _wrap_TasmanianSparseGrid_getAccelerationType(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TypeAcceleration result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getAccelerationType() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (TasGrid::TypeAcceleration)((TasGrid::TasmanianSparseGrid const *)arg1)->getAccelerationType(); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_isAccelerationAvailable(int const *farg1) { int fresult ; TasGrid::TypeAcceleration arg1 ; bool result; arg1 = (TasGrid::TypeAcceleration)(*farg1); result = (bool)TasGrid::TasmanianSparseGrid::isAccelerationAvailable(arg1); fresult = (result ? 1 : 0); return fresult; } SWIGEXPORT void _wrap_TasmanianSparseGrid_setGPUID(SwigClassWrapper *farg1, int const *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setGPUID(int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); (arg1)->setGPUID(arg2); } SWIGEXPORT int _wrap_TasmanianSparseGrid_getGPUID(SwigClassWrapper *farg1) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::getGPUID() const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = (int)((TasGrid::TasmanianSparseGrid const *)arg1)->getGPUID(); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getNumGPUs() { int fresult ; int result; result = (int)TasGrid::TasmanianSparseGrid::getNumGPUs(); fresult = (int)(result); return fresult; } SWIGEXPORT int _wrap_TasmanianSparseGrid_getGPUMemory(int const *farg1) { int fresult ; int arg1 ; int result; arg1 = (int)(*farg1); result = (int)TasGrid::TasmanianSparseGrid::getGPUMemory(arg1); fresult = (int)(result); return fresult; } SWIGEXPORT SwigArrayWrapper _wrap_TasmanianSparseGrid_getGPUName(int const *farg1) { SwigArrayWrapper fresult ; int arg1 ; std::string result; arg1 = (int)(*farg1); result = TasGrid::TasmanianSparseGrid::getGPUName(arg1); fresult.size = (&result)->size(); if (fresult.size > 0) { fresult.data = malloc(fresult.size); memcpy(fresult.data, (&result)->c_str(), fresult.size); } else { fresult.data = NULL; } return fresult; } SWIGEXPORT void _wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_0(SwigClassWrapper *farg1, double const *farg2, int const *farg3, double *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double arg2 ; int arg3 ; double *arg4 = (double *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::removePointsByHierarchicalCoefficient(double,int,double const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double)(*farg2); arg3 = (int)(*farg3); arg4 = (double *)(farg4); (arg1)->removePointsByHierarchicalCoefficient(arg2,arg3,(double const *)arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_1(SwigClassWrapper *farg1, double const *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double arg2 ; int arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::removePointsByHierarchicalCoefficient(double,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double)(*farg2); arg3 = (int)(*farg3); (arg1)->removePointsByHierarchicalCoefficient(arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_2(SwigClassWrapper *farg1, double const *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::removePointsByHierarchicalCoefficient(double)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double)(*farg2); (arg1)->removePointsByHierarchicalCoefficient(arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_3(SwigClassWrapper *farg1, int const *farg2, int const *farg3, double *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; double *arg4 = (double *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::removePointsByHierarchicalCoefficient(int,int,double const *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); arg4 = (double *)(farg4); (arg1)->removePointsByHierarchicalCoefficient(arg2,arg3,(double const *)arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_4(SwigClassWrapper *farg1, int const *farg2, int const *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; int arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::removePointsByHierarchicalCoefficient(int,int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); (arg1)->removePointsByHierarchicalCoefficient(arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_removePointsByHierarchicalCoefficient__SWIG_5(SwigClassWrapper *farg1, int const *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int arg2 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::removePointsByHierarchicalCoefficient(int)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); (arg1)->removePointsByHierarchicalCoefficient(arg2); } SWIGEXPORT int _wrap_TasmanianSparseGrid_evaluateSparseHierarchicalFunctionsGetNZ(SwigClassWrapper *farg1, double *farg2, int const *farg3) { int fresult ; TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; int arg3 ; int result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluateSparseHierarchicalFunctionsGetNZ(double const [],int) const", return 0); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (int)(*farg3); result = (int)((TasGrid::TasmanianSparseGrid const *)arg1)->evaluateSparseHierarchicalFunctionsGetNZ((double const (*))arg2,arg3); fresult = (int)(result); return fresult; } SWIGEXPORT void _wrap_TasmanianSparseGrid_evaluateSparseHierarchicalFunctionsStatic(SwigClassWrapper *farg1, double *farg2, int const *farg3, int *farg4, int *farg5, double *farg6) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; int arg3 ; int *arg4 ; int *arg5 ; double *arg6 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluateSparseHierarchicalFunctionsStatic(double const [],int,int [],int [],double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (int)(*farg3); arg4 = (int *)(farg4); arg5 = (int *)(farg5); arg6 = (double *)(farg6); ((TasGrid::TasmanianSparseGrid const *)arg1)->evaluateSparseHierarchicalFunctionsStatic((double const (*))arg2,arg3,arg4,arg5,arg6); } SWIGEXPORT void _wrap_TasmanianSparseGrid_evaluateFast__SWIG_0(SwigClassWrapper *farg1, double *farg2, double *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; double *arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluateFast< double >(double const [],double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (double *)(farg3); ((TasGrid::TasmanianSparseGrid const *)arg1)->SWIGTEMPLATEDISAMBIGUATOR evaluateFast< double >((double const (*))arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_evaluateFast__SWIG_2(SwigClassWrapper *farg1, float *farg2, float *farg3) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; float *arg2 ; float *arg3 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluateFast< float >(float const [],float []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (float *)(farg2); arg3 = (float *)(farg3); ((TasGrid::TasmanianSparseGrid const *)arg1)->SWIGTEMPLATEDISAMBIGUATOR evaluateFast< float >((float const (*))arg2,arg3); } SWIGEXPORT void _wrap_TasmanianSparseGrid_evaluateBatchGPU__SWIG_0(SwigClassWrapper *farg1, double *farg2, int const *farg3, double *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; double *arg2 ; int arg3 ; double *arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluateBatchGPU< double >(double const [],int,double []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (double *)(farg2); arg3 = (int)(*farg3); arg4 = (double *)(farg4); ((TasGrid::TasmanianSparseGrid const *)arg1)->SWIGTEMPLATEDISAMBIGUATOR evaluateBatchGPU< double >((double const (*))arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_evaluateBatchGPU__SWIG_1(SwigClassWrapper *farg1, float *farg2, int const *farg3, float *farg4) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; float *arg2 ; int arg3 ; float *arg4 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::evaluateBatchGPU< float >(float const [],int,float []) const", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (float *)(farg2); arg3 = (int)(*farg3); arg4 = (float *)(farg4); ((TasGrid::TasmanianSparseGrid const *)arg1)->SWIGTEMPLATEDISAMBIGUATOR evaluateBatchGPU< float >((float const (*))arg2,arg3,arg4); } SWIGEXPORT void _wrap_TasmanianSparseGrid_setConformalTransformASIN__SWIG_1(SwigClassWrapper *farg1, int *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; int *arg2 = (int *) 0 ; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid *", "TasmanianSparseGrid", "TasGrid::TasmanianSparseGrid::setConformalTransformASIN(int *)", return ); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int *)(farg2); TasGrid_TasmanianSparseGrid_setConformalTransformASIN__SWIG_1(arg1,arg2); } SWIGEXPORT void _wrap_TasmanianSparseGrid_op_assign__(SwigClassWrapper *farg1, SwigClassWrapper *farg2) { TasGrid::TasmanianSparseGrid *arg1 = (TasGrid::TasmanianSparseGrid *) 0 ; TasGrid::TasmanianSparseGrid *arg2 = 0 ; (void)sizeof(arg1); (void)sizeof(arg2); SWIG_assign(farg1, *farg2); } SWIGEXPORT SwigClassWrapper _wrap_TasmanianReadGrid(SwigArrayWrapper *farg1) { SwigClassWrapper fresult ; char *arg1 = (char *) 0 ; TasGrid::TasmanianSparseGrid result; arg1 = (char *)(farg1->data); result = TasGrid::readGrid((char const *)arg1); fresult.cptr = new (TasGrid::TasmanianSparseGrid)(result); fresult.cmemflags = SWIG_MEM_RVALUE | SWIG_MEM_OWN; return fresult; } SWIGEXPORT SwigClassWrapper _wrap_TasmanianCopyGrid__SWIG_0(SwigClassWrapper *farg1, int const *farg2, int const *farg3) { SwigClassWrapper fresult ; TasGrid::TasmanianSparseGrid *arg1 = 0 ; int arg2 ; int arg3 ; TasGrid::TasmanianSparseGrid result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const &", "TasmanianSparseGrid", "TasGrid::copyGrid(TasGrid::TasmanianSparseGrid const &,int,int)", return SwigClassWrapper_uninitialized()); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); arg3 = (int)(*farg3); result = TasGrid::copyGrid((TasGrid::TasmanianSparseGrid const &)*arg1,arg2,arg3); fresult.cptr = new (TasGrid::TasmanianSparseGrid)(result); fresult.cmemflags = SWIG_MEM_RVALUE | SWIG_MEM_OWN; return fresult; } SWIGEXPORT SwigClassWrapper _wrap_TasmanianCopyGrid__SWIG_1(SwigClassWrapper *farg1, int const *farg2) { SwigClassWrapper fresult ; TasGrid::TasmanianSparseGrid *arg1 = 0 ; int arg2 ; TasGrid::TasmanianSparseGrid result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const &", "TasmanianSparseGrid", "TasGrid::copyGrid(TasGrid::TasmanianSparseGrid const &,int)", return SwigClassWrapper_uninitialized()); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; arg2 = (int)(*farg2); result = TasGrid::copyGrid((TasGrid::TasmanianSparseGrid const &)*arg1,arg2); fresult.cptr = new (TasGrid::TasmanianSparseGrid)(result); fresult.cmemflags = SWIG_MEM_RVALUE | SWIG_MEM_OWN; return fresult; } SWIGEXPORT SwigClassWrapper _wrap_TasmanianCopyGrid__SWIG_2(SwigClassWrapper *farg1) { SwigClassWrapper fresult ; TasGrid::TasmanianSparseGrid *arg1 = 0 ; TasGrid::TasmanianSparseGrid result; SWIG_check_nonnull(farg1->cptr, "TasGrid::TasmanianSparseGrid const &", "TasmanianSparseGrid", "TasGrid::copyGrid(TasGrid::TasmanianSparseGrid const &)", return SwigClassWrapper_uninitialized()); arg1 = (TasGrid::TasmanianSparseGrid *)farg1->cptr; result = TasGrid::copyGrid((TasGrid::TasmanianSparseGrid const &)*arg1); fresult.cptr = new (TasGrid::TasmanianSparseGrid)(result); fresult.cmemflags = SWIG_MEM_RVALUE | SWIG_MEM_OWN; return fresult; } } // extern TASMANIAN-8.1/InterfaceSwig/mpi.i000066400000000000000000000012231470551176200163740ustar00rootroot00000000000000%{ #include %} /* ------------------------------------------------------------------------- * \brief MPI Fortran compatibility datatypes * * Use MPI/Fortran compatibility code to wrap C MPI types, but use ISO-C * compatibility layer to pass the Fortran integers (and convert back to native * MPI type in the wrapper result code). */ %apply int { MPI_Comm }; %typemap(ftype) MPI_Comm "integer" %typemap(fin) MPI_Comm "$1 = int($input, C_INT)" %typemap(fout) MPI_Comm "$result = int($1)" %typemap(in, noblock=1) MPI_Comm { $1 = MPI_Comm_f2c((MPI_Fint)*$input); } %typemap(out, noblock=1) MPI_Comm { $result = (int)MPI_Comm_c2f($1); } TASMANIAN-8.1/InterfaceSwig/swig.sh000077500000000000000000000004301470551176200167440ustar00rootroot00000000000000#!/bin/sh if [ "$HOSTNAME" == "vostok" ]; then export PATH=/rnsdhpc/code/build/swig-debug:$PATH export SWIG_LIB=/rnsdhpc/code/src/swig/Lib fi exec swig -fortran -c++ -I../SparseGrids \ -fext f03 \ -outdir generated -o generated/tasmanianFORTRAN_wrap.cxx \ tasmanian.i TASMANIAN-8.1/InterfaceSwig/tasmanian_mpi_swig.i000066400000000000000000000044351470551176200214700ustar00rootroot00000000000000/*! * \file tasmanian.i * * Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. * Distributed under a BSD 3-Clause License: see LICENSE for details. */ %module "tasmanian_mpi_swig" /* ------------------------------------------------------------------------- * Header definition macros * ------------------------------------------------------------------------- */ %define %tasmanian_add_header %insert("fbegin") %{ ! TASMANIAN project, https://github.com/ORNL/TASMANIAN ! Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. ! Distributed under an MIT open source license: see LICENSE for details. %} %insert("begin") %{ /* * TASMANIAN project, https://github.com/ORNL/TASMANIAN * Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. * Distributed under an MIT open source license: see LICENSE for details. */ %} %enddef %tasmanian_add_header /* ------------------------------------------------------------------------- * Exception handling * ------------------------------------------------------------------------- */ // Rename the error variables' internal C symbols #define SWIG_FORTRAN_ERROR_INT tasmanian_ierr #define SWIG_FORTRAN_ERROR_STR tasmanian_get_serr %include /* ------------------------------------------------------------------------- * Data types and instantiation * ------------------------------------------------------------------------- */ // Note: stdint.i inserts #include %include // Support std::string %include %include "mpi.i" %import tasmanian_swig.i %ignore std::basic_streambuf>; %ignore TasGrid::VectorToStreamBuffer; %ignore getMPIRank(MPI_Comm comm); #define Tasmanian_ENABLE_MPI %{ #include %} %include "tsgMPIScatterGrid.hpp" %rename(tsgMPIGridSend) TasGrid::MPIGridSend; %template(tsgMPIGridSendBin) TasGrid::MPIGridSend; %rename(tsgMPIGridRecv) TasGrid::MPIGridRecv; %template(tsgMPIGridRecvBin) TasGrid::MPIGridRecv; %rename(tsgMPIGridBcast) TasGrid::MPIGridBcast; %template(tsgMPIGridBcastBin) TasGrid::MPIGridBcast; %rename(tsgMPIGridScatterOutputs) TasGrid::MPIGridScatterOutputs; %template(tsgMPIGridScatterOutputsBin) TasGrid::MPIGridScatterOutputs; TASMANIAN-8.1/InterfaceSwig/tasmanian_swig.i000066400000000000000000000040531470551176200206170ustar00rootroot00000000000000/*! * \file tasmanian.i * * Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. * Distributed under a BSD 3-Clause License: see LICENSE for details. */ %module "tasmanian_swig" /* ------------------------------------------------------------------------- * Header definition macros * ------------------------------------------------------------------------- */ %define %tasmanian_add_header %insert("fbegin") %{ ! TASMANIAN project, https://github.com/ORNL/TASMANIAN ! Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. ! Distributed under an MIT open source license: see LICENSE for details. %} %insert("begin") %{ /* * TASMANIAN project, https://github.com/ORNL/TASMANIAN * Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. * Distributed under an MIT open source license: see LICENSE for details. */ %} %enddef %tasmanian_add_header /* ------------------------------------------------------------------------- * Exception handling * ------------------------------------------------------------------------- */ // Rename the error variables' internal C symbols #define SWIG_FORTRAN_ERROR_INT tasmanian_ierr #define SWIG_FORTRAN_ERROR_STR tasmanian_get_serr // Restore names in the wrapper code %rename(ierr) tasmanian_ierr; %rename(get_serr) tasmanian_get_serr; %include /* ------------------------------------------------------------------------- * Data types and instantiation * ------------------------------------------------------------------------- */ // Note: stdint.i inserts #include %include // Support std::string %include // Unless otherwise specified, ignore functions that use unknown types %fortranonlywrapped; // Prefix all enums with "tsg" %rename("tsg_%s",%$isenumitem) ""; %rename("tsg_%s",%$isenum) ""; /* ------------------------------------------------------------------------- * Wrapped files * ------------------------------------------------------------------------- */ %include "tsgEnumerates.i" %include "TasmanianSparseGrid.i" TASMANIAN-8.1/InterfaceSwig/tsgEnumerates.i000066400000000000000000000005761470551176200204470ustar00rootroot00000000000000/*! * \file tsgEnumerates.i * * Copyright (c) 2020 Oak Ridge National Laboratory, UT-Battelle, LLC. * Distributed under a BSD 3-Clause License: see LICENSE for details. */ %{ #include "tsgEnumerates.hpp" %} // Wrap types found in this file as native fortran enums %fortranconst; %ignore accel_gpu_hip; %ignore accel_gpu_rocblas; %include "tsgEnumerates.hpp" %nofortranconst; TASMANIAN-8.1/InterfaceTPL/000077500000000000000000000000001470551176200151655ustar00rootroot00000000000000TASMANIAN-8.1/InterfaceTPL/tsgBlasNull.hpp000066400000000000000000000076511470551176200201410ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_BLAS_NULL_HPP #define __TASMANIAN_BLAS_NULL_HPP /*! * \file tsgBlasNull.hpp * \brief Wrappers to no-op functions with BLAS signature. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * Removed the need for preprocessor directives by providing methods * with the correct signature but are no-op. */ namespace TasBLAS{ inline double norm2(int, double const[], int){ return 0.0; } inline void vswap(int, double[], int, double[], int){} inline void scal(int, double, double[], int){} inline void gemv(char, int, int, double, double const[], int, double const[], int, double, double[], int){} inline void trsv(char, char, char, int, double const[], int, double[], int){} template inline void trsm(char, char, char, char, int, int, T, T const[], int, T[], int){} inline void getrf(int, int, double[], int, int[]){} inline void getrs(char, int, int, double const[], int, int const[], double[], int){} inline void sterf(int, double[], double[]){} template inline void denseMultiply(int, int, int, T, const T[], const T[], T, T[]){} template inline void solveLS(char, int, int, scalar_type[], scalar_type[], int = 1){} template inline void factorizeLQ(int, int, scalar_type[], std::vector &){} template inline void multiplyQ(int, int, int, scalar_type const[], std::vector const&, scalar_type[]){} template void solveLSmulti(int, int, scalar_type[], int, scalar_type[]){} } #endif TASMANIAN-8.1/InterfaceTPL/tsgBlasWrappers.hpp000066400000000000000000000532011470551176200210220ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_BLAS_WRAPPERS_HPP #define __TASMANIAN_BLAS_WRAPPERS_HPP #include "tsgEnumerates.hpp" /*! * \internal * \file tsgBlasWrappers.hpp * \brief Wrappers to BLAS functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * The header contains a inline wrappers that give C++ style of * interface to BLAS operations. * \endinternal */ #ifndef __TASMANIAN_DOXYGEN_SKIP extern "C"{ // Skip the definitions from Doxygen, this serves as a mock-up header for the BLAS API. // BLAS level 1 double dnrm2_(const int *N, const double *x, const int *incx); void dswap_(const int *N, double *x, const int *incx, double *y, const int *incy); void dscal_(const int *N, const double *alpha, const double *x, const int *incx); // BLAS level 2 void dgemv_(const char *transa, const int *M, const int *N, const double *alpha, const double *A, const int *lda, const double *x, const int *incx, const double *beta, const double *y, const int *incy); void dtrsv_(const char *uplo, const char *trans, const char *diag, const int *N, const double *A, const int *lda, double *x, const int *incx); // BLAS level 3 void dgemm_(const char* transa, const char* transb, const int *m, const int *n, const int *k, const double *alpha, const double *A, const int *lda, const double *B, const int *ldb, const double *beta, const double *C, const int *ldc); void dtrsm_(const char *side, const char *uplo, const char *trans, const char *diag, const int *M, const int *N, const double *alpha, const double *A, const int *lda, double *B, const int *ldb); void ztrsm_(const char *side, const char *uplo, const char *trans, const char *diag, const int *M, const int *N, const std::complex *alpha, const std::complex *A, const int *lda, std::complex *B, const int *ldb); // LAPACK solvers // General PLU factorize/solve void dgetrf_(const int *M, const int *N, double *A, const int *lda, int *ipiv, int *info); void dgetrs_(const char *trans, const int *N, const int *nrhs, const double *A, const int *lda, const int *ipiv, double *B, const int *ldb, int *info); // General least-squares solve void dgels_(const char *trans, const int *M, const int *N, const int *nrhs, double *A, const int *lda, double *B, const int *ldb, double *work, int *lwork, int *info); void zgels_(const char *trans, const int *M, const int *N, const int *nrhs, std::complex *A, const int *lda, std::complex *B, const int *ldb, std::complex *work, int *lwork, int *info); // Symmetric tridiagonal eigenvalue compute void dstebz_(const char *range, const char *order, const int *N, const double *vl, const double *vu, const int *il, const int *iu, const double *abstol, const double D[], const double E[], int *M, int *nsplit, double W[], int iblock[], int isplit[], double work[], int iwork[], int *info); void dsteqr_(const char *compz, const int *N, double D[], double E[], double Z[], const int *ldz, double work[], int *info); void dsterf_(const int *N, double D[], double E[], int *info); // General LQ-factorize and multiply by Q #ifdef Tasmanian_BLAS_HAS_ZGELQ void dgelq_(const int *M, const int *N, double *A, const int *lda, double *T, int const *Tsize, double *work, int const *lwork, int *info); void dgemlq_(const char *side, const char *trans, const int *M, const int *N, const int *K, double const *A, int const *lda, double const *T, int const *Tsize, double C[], int const *ldc, double *work, int const *lwork, int *info); void zgelq_(const int *M, const int *N, std::complex *A, const int *lda, std::complex *T, int const *Tsize, std::complex *work, int const *lwork, int *info); void zgemlq_(const char *side, const char *trans, const int *M, const int *N, const int *K, std::complex const *A, int const *lda, std::complex const *T, int const *Tsize, std::complex C[], int const *ldc, std::complex *work, int const *lwork, int *info); #endif } #endif /*! * \ingroup TasmanianTPLWrappers * \brief Wrappers for BLAS and LAPACK methods (hidden internal namespace). */ namespace TasBLAS{ /*! * \ingroup TasmanianTPLWrappers * \brief BLAS dnrm2 */ inline double norm2(int N, double const x[], int incx){ return dnrm2_(&N, x, &incx); } /*! * \ingroup TasmanianTPLWrappers * \brief BLAS dswap */ inline void vswap(int N, double x[], int incx, double y[], int incy){ dswap_(&N, x, &incx, y, &incy); } /*! * \ingroup TasmanianTPLWrappers * \brief BLAS dscal */ inline void scal(int N, double alpha, double x[], int incx){ dscal_(&N, &alpha, x, &incx); } /*! * \ingroup TasmanianTPLWrappers * \brief BLAS dgemv */ inline void gemv(char trans, int M, int N, double alpha, double const A[], int lda, double const x[], int incx, double beta, double y[], int incy){ dgemv_(&trans, &M, &N, &alpha, A, &lda, x, &incx, &beta, y, &incy); } /*! * \ingroup TasmanianTPLWrappers * \brief BLAS dtrsv */ inline void trsv(char uplo, char trans, char diag, int N, double const A[], int lda, double x[], int incx){ dtrsv_(&uplo, &trans, &diag, &N, A, &lda, x, &incx); } /*! * \ingroup TasmanianTPLWrappers * \brief BLAS gemm */ inline void gemm(char transa, char transb, int M, int N, int K, double alpha, double const A[], int lda, double const B[], int ldb, double beta, double C[], int ldc){ dgemm_(&transa, &transb, &M, &N, &K, &alpha, A, &lda, B, &ldb, &beta, C, &ldc); } /*! * \ingroup TasmanianTPLWrappers * \brief BLAS dtrsm */ inline void trsm(char side, char uplo, char trans, char diag, int M, int N, double alpha, double const A[], int lda, double B[], int ldb){ dtrsm_(&side, &uplo, &trans, &diag, &M, &N, &alpha, A, &lda, B, &ldb); } /*! * \ingroup TasmanianTPLWrappers * \brief BLAS ztrsm */ inline void trsm(char side, char uplo, char trans, char diag, int M, int N, std::complex alpha, std::complex const A[], int lda, std::complex B[], int ldb){ ztrsm_(&side, &uplo, &trans, &diag, &M, &N, &alpha, A, &lda, B, &ldb); } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK dgetrf */ inline void getrf(int M, int N, double A[], int lda, int ipiv[]){ int info = 0; dgetrf_(&M, &N, A, &lda, ipiv, &info); if (info != 0) throw std::runtime_error(std::string("Lapack dgetrf_ exited with code: ") + std::to_string(info)); } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK dgetrs */ inline void getrs(char trans, int N, int nrhs, double const A[], int lda, int const ipiv[], double B[], int ldb){ int info = 0; dgetrs_(&trans, &N, &nrhs, A, &lda, ipiv, B, &ldb, &info); if (info != 0) throw std::runtime_error(std::string("Lapack dgetrs_ exited with code: ") + std::to_string(info)); } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK dgels */ inline void gels(char trans, int M, int N, int nrhs, double A[], int lda, double B[], int ldb, double work[], int lwork){ int info = 0; dgels_(&trans, &M, &N, &nrhs, A, &lda, B, &ldb, work, &lwork, &info); if (info != 0){ if (lwork > 0) throw std::runtime_error(std::string("Lapack dgels_ solve-stage exited with code: ") + std::to_string(info)); else throw std::runtime_error(std::string("Lapack dgels_ infer-worksize-stage exited with code: ") + std::to_string(info)); } } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK zgels */ inline void gels(char trans, int M, int N, int nrhs, std::complex A[], int lda, std::complex B[], int ldb, std::complex work[], int lwork){ int info = 0; zgels_(&trans, &M, &N, &nrhs, A, &lda, B, &ldb, work, &lwork, &info); if (info != 0){ if (lwork > 0) throw std::runtime_error(std::string("Lapack zgels_ solve-stage exited with code: ") + std::to_string(info)); else throw std::runtime_error(std::string("Lapack zgels_ infer-worksize-stage exited with code: ") + std::to_string(info)); } } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK dstebz */ inline void stebz(char range, char order, int N, double vl, double vu, int il, int iu, double abstol, double D[], double E[], int& M, int& nsplit, double W[], int iblock[], int isplit[], double work[], int iwork[]) { int info = 0; dstebz_(&range, &order, &N, &vl, &vu, &il, &iu, &abstol, D, E, &M, &nsplit, W, iblock, isplit, work, iwork, &info); if (info != 0) { if (info <= 3) { throw std::runtime_error( std::string( "Lapack dstebz_ failed to converge for some eigenvalues and exited with code: ") + std::to_string(info)); } else if (info == 4) { throw std::runtime_error( std::string("Lapack dstebz_ used a Gershgorin interval that was too small and exited with code: ") + std::to_string(info)); } else if (info > 4) { throw std::runtime_error( std::string("Lapack dstebz_ failed and exited with code: ") + std::to_string(info)); } else { throw std::runtime_error( std::string( "Lapack dstebz_ had an illegal value at argument number: ") + std::to_string(-info)); } } } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK dsteqr */ inline void steqr(char compz, int N, double D[], double E[], double Z[], int ldz, double work[]) { int info = 0; dsteqr_(&compz, &N, D, E, Z, &ldz, work, &info); if (info != 0) { if (info > 0) { throw std::runtime_error( std::string("Lapack dsteqr_ failed to converge for some eigenvalues and exited with code: ") + std::to_string(info)); } else { throw std::runtime_error( std::string("Lapack dsteqr_ had an illegal value at argument number: ") + std::to_string(-info)); } } } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK dsterf */ inline void sterf(int N, double D[], double E[]) { int info = 0; dsterf_(&N, D, E, &info); if (info != 0) { if (info > 0) { throw std::runtime_error( std::string("Lapack dsteqr_ failed to converge for some eigenvalues and exited with code: ") + std::to_string(info)); } else { throw std::runtime_error( std::string("Lapack dsteqr_ had an illegal value at argument number: ") + std::to_string(-info)); } } } #ifdef Tasmanian_BLAS_HAS_ZGELQ /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK dgeql */ inline void geql(int M, int N, double A[], int lda, double T[], int Tsize, double work[], int lwork){ int info = 0; dgelq_(&M, &N, A, &lda, T, &Tsize, work, &lwork, &info); if (info != 0){ if (lwork > 0) throw std::runtime_error(std::string("Lapack dgeql_ factorize-stage exited with code: ") + std::to_string(info)); else throw std::runtime_error(std::string("Lapack dgeql_ infer-worksize-stage exited with code: ") + std::to_string(info)); } } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK dgemlq */ inline void gemlq(char side, char trans, int M, int N, int K, double const A[], int lda, double const T[], int Tsize, double C[], int ldc, double work[], int lwork){ int info = 0; dgemlq_(&side, &trans, &M, &N, &K, A, &lda, T, &Tsize, C, &ldc, work, &lwork, &info); if (info != 0){ if (lwork > 0) throw std::runtime_error(std::string("Lapack dgemlq_ compute-stage exited with code: ") + std::to_string(info)); else throw std::runtime_error(std::string("Lapack dgemlq_ infer-worksize-stage exited with code: ") + std::to_string(info)); } } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK zgeql */ inline void geql(int M, int N, std::complex A[], int lda, std::complex T[], int Tsize, std::complex work[], int lwork){ int info = 0; zgelq_(&M, &N, A, &lda, T, &Tsize, work, &lwork, &info); if (info != 0){ if (lwork > 0) throw std::runtime_error(std::string("Lapack zgeql_ factorize-stage exited with code: ") + std::to_string(info)); else throw std::runtime_error(std::string("Lapack zgeql_ infer-worksize-stage exited with code: ") + std::to_string(info)); } } /*! * \ingroup TasmanianTPLWrappers * \brief LAPACK zgemlq */ inline void gemlq(char side, char trans, int M, int N, int K, std::complex const A[], int lda, std::complex const T[], int Tsize, std::complex C[], int ldc, std::complex work[], int lwork){ int info = 0; zgemlq_(&side, &trans, &M, &N, &K, A, &lda, T, &Tsize, C, &ldc, work, &lwork, &info); if (info != 0){ if (lwork > 0) throw std::runtime_error(std::string("Lapack zgemlq_ compute-stage exited with code: ") + std::to_string(info)); else throw std::runtime_error(std::string("Lapack zgemlq_ infer-worksize-stage exited with code: ") + std::to_string(info)); } } #endif // higher-level methods building on top of one or more BLAS/LAPACK Methods /*! * \ingroup TasmanianTPLWrappers * \brief Returns the square of the norm of the vector. */ template inline T norm2_2(int N, T const x[]){ T nrm = norm2(N, x, 1); return nrm * nrm; } /*! * \ingroup TasmanianTPLWrappers * \brief Combination of BLAS gemm and gemv * * Computes \f$ C = \alpha A B + \beta C \f$ where A is M by K, B is K by N, and C is M by N. * The method uses both gemm() and gemv() to handle the cases when either dimension is one. */ template inline void denseMultiply(int M, int N, int K, T alpha, const T A[], const T B[], T beta, T C[]){ if (M > 1){ if (N > 1){ // matrix mode gemm('N', 'N', M, N, K, alpha, A, M, B, K, beta, C, M); }else{ // matrix vector, A * v = C gemv('N', M, K, alpha, A, M, B, 1, beta, C, 1); } }else{ // matrix vector B^T * v = C gemv('T', K, N, alpha, B, K, A, 1, beta, C, 1); } } /*! * \ingroup TasmanianTPLWrappers * \brief Conjugates a matrix, no op in the real case. */ inline void conj_matrix(int, int, double[]){} /*! * \ingroup TasmanianTPLWrappers * \brief Conjugates the matrix, used in the case when 'T' operation is needed by only 'C' is available in the LAPACK standard. */ inline void conj_matrix(int N, int M, std::complex A[]){ for(size_t i=0; i(N) * static_cast(M); i++) A[i] = std::conj(A[i]); } /*! * \ingroup TasmanianTPLWrappers * \brief Returns the transpose symbol, 'T' in the real case. */ constexpr inline char get_trans(double){ return 'T'; } /*! * \ingroup TasmanianTPLWrappers * \brief Returns the conjugate-transpose symbol, 'C' in the complex case. */ constexpr inline char get_trans(std::complex){ return 'C'; } /*! * \ingroup TasmanianTPLWrappers * \brief Solves the over-determined least squares problem with single right-hand-side. * * Note that trans must be a capital letter N or T. */ template inline void solveLS(char trans, int N, int M, scalar_type A[], scalar_type b[], int nrhs = 1){ std::vector work(1); int n = (trans == 'N') ? N : M; int m = (trans == 'N') ? M : N; char effective_trans = (trans == 'N') ? trans : get_trans(static_cast(0.0)); conj_matrix(N, M, A); // does nothing in the real case, computes the conjugate in the complex one TasBLAS::gels(effective_trans, n, m, nrhs, A, n, b, N, work.data(), -1); work.resize(static_cast(std::real(work[0]))); TasBLAS::gels(effective_trans, n, m, nrhs, A, n, b, N, work.data(), static_cast(work.size())); } /*! * \ingroup TasmanianTPLWrappers * \brief Compute the LQ factorization of the matrix \b A. * * The assumption here is that the matrix is in column major format, otherwise this computes the QR factorization. * In fact, the Tasmanian uses this method to compute QR of a row-major matrix. */ template inline void factorizeLQ(int rows, int cols, scalar_type A[], std::vector &T){ T.resize(5); std::vector work(1); geql(rows, cols, A, rows, T.data(), -1, work.data(), -1); T.resize(static_cast(std::real(T[0]))); work.resize(static_cast(std::real(work[0]))); geql(rows, cols, A, rows, T.data(), static_cast(T.size()), work.data(), static_cast(work.size())); } /*! * \ingroup TasmanianTPLWrappers * \brief Multiplies C by the Q factor computed with factorizeLQ. * * Computes \f$ C = C Q^T \f$ where Q comes from the call to factorizeLQ. * The matrix C has dimensions M by N, A has dimensions K by N. */ template inline void multiplyQ(int M, int N, int K, scalar_type const A[], std::vector const &T, scalar_type C[]){ std::vector work(1); gemlq('R', get_trans(static_cast(0.0)), M, N, K, A, K, T.data(), static_cast(T.size()), C, M, work.data(), -1); work.resize(static_cast(std::real(work[0]))); gemlq('R', get_trans(static_cast(0.0)), M, N, K, A, K, T.data(), static_cast(T.size()), C, M, work.data(), static_cast(work.size())); } /*! * \ingroup TasmanianTPLWrappers * \brief Solves the least-squares assuming row-major format, see TasmanianDenseSolver::solvesLeastSquares() */ template void solveLSmulti(int n, int m, scalar_type A[], int nrhs, scalar_type B[]){ if (nrhs == 1){ TasBLAS::solveLS('T', n, m, A, B); }else{ #ifdef Tasmanian_BLAS_HAS_ZGELQ std::vector T; TasBLAS::factorizeLQ(m, n, A, T); TasBLAS::multiplyQ(nrhs, n, m, A, T, B); TasBLAS::trsm('R', 'L', 'N', 'N', nrhs, m, 1.0, A, m, B, nrhs); #else auto Bcols = TasGrid::Utils::transpose(nrhs, n, B); TasBLAS::solveLS('T', n, m, A, Bcols.data(), nrhs); TasGrid::Utils::transpose(n, nrhs, Bcols.data(), B); #endif } } } #endif TASMANIAN-8.1/InterfaceTPL/tsgCudaWrappers.cpp000066400000000000000000001035511470551176200210140ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_CUDA_WRAPPERS_CPP #define __TASMANIAN_CUDA_WRAPPERS_CPP #include "tsgGpuWrappers.hpp" #include "tsgCudaWrappers.hpp" /*! * \file tsgCudaWrappers.cpp * \brief Wrappers to CUDA functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * Realizations of the GPU algorithms using the CUDA backend. */ namespace TasGrid{ /* * Meta methods */ template void GpuVector::resize(AccelerationContext const*, size_t count){ if (count != num_entries){ // if the current array is not big enough clear(); // resets dynamic_mode num_entries = count; TasGpu::cucheck( cudaMalloc(((void**) &gpu_data), num_entries * sizeof(T)), "cudaMalloc()"); } } template void GpuVector::clear(){ num_entries = 0; if (gpu_data != nullptr) // if I own the data and the data is not null TasGpu::cucheck( cudaFree(gpu_data), "cudaFree()"); gpu_data = nullptr; } template void GpuVector::load(AccelerationContext const *acc, size_t count, const T* cpu_data){ resize(acc, count); TasGpu::cucheck( cudaMemcpy(gpu_data, cpu_data, num_entries * sizeof(T), cudaMemcpyHostToDevice), "cudaMemcpy() to device"); } template void GpuVector::unload(AccelerationContext const*, size_t num, T* cpu_data) const{ TasGpu::cucheck( cudaMemcpy(cpu_data, gpu_data, num * sizeof(T), cudaMemcpyDeviceToHost), "cudaMemcpy() from device"); } template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const double*); template void GpuVector::unload(AccelerationContext const*, size_t, double*) const; template void GpuVector>::resize(AccelerationContext const*, size_t); template void GpuVector>::clear(); template void GpuVector>::load(AccelerationContext const*, size_t, const std::complex*); template void GpuVector>::unload(AccelerationContext const*, size_t, std::complex*) const; template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const float*); template void GpuVector::unload(AccelerationContext const*, size_t, float*) const; template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const int*); template void GpuVector::unload(AccelerationContext const*, size_t, int*) const; template<> void deleteHandle(int *p){ cublasDestroy(reinterpret_cast(p)); } template<> void deleteHandle(int *p){ cusparseDestroy(reinterpret_cast(p)); } template<> void deleteHandle(int *p){ cusolverDnDestroy(reinterpret_cast(p)); } void GpuEngine::setCuBlasHandle(void *handle){ cublas_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter(false)); } void GpuEngine::setCuSparseHandle(void *handle){ cusparse_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter(false)); } void GpuEngine::setCuSolverDnHandle(void *handle){ cusolver_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter(false)); } int AccelerationMeta::getNumGpuDevices(){ int gpu_count = 0; TasGpu::cucheck( cudaGetDeviceCount(&gpu_count), "cudaGetDeviceCount()"); return gpu_count; } void AccelerationMeta::setDefaultGpuDevice(int deviceID){ cudaSetDevice(deviceID); } unsigned long long AccelerationMeta::getTotalGPUMemory(int deviceID){ cudaDeviceProp prop; cudaGetDeviceProperties(&prop, deviceID); return prop.totalGlobalMem; } std::string AccelerationMeta::getGpuDeviceName(int deviceID){ if ((deviceID < 0) || (deviceID >= getNumGpuDevices())) return std::string(); cudaDeviceProp prop; cudaGetDeviceProperties(&prop, deviceID); return std::string(prop.name); } template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const T *gpu_data, std::vector &cpu_data){ cpu_data.resize(num_entries); TasGpu::cucheck( cudaMemcpy(cpu_data.data(), gpu_data, num_entries * sizeof(T), cudaMemcpyDeviceToHost), "cudaRecv(type, type)"); } template void AccelerationMeta::delGpuArray(AccelerationContext const*, T *x){ TasGpu::cucheck( cudaFree(x), "cudaFree() in delCudaArray()"); } void* AccelerationMeta::createCublasHandle(){ cublasHandle_t handle; cublasCreate(&handle); return (void*) handle; } void AccelerationMeta::deleteCublasHandle(void *handle){ cublasDestroy(reinterpret_cast(handle)); } template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const double*, std::vector&); template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const float*, std::vector&); template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const int*, std::vector&); template void AccelerationMeta::delGpuArray(AccelerationContext const*, double*); template void AccelerationMeta::delGpuArray(AccelerationContext const*, float*); template void AccelerationMeta::delGpuArray(AccelerationContext const*, int*); namespace TasGpu{ /* * cuBLAS section */ //! \brief Converts character to cublas operation. constexpr cublasOperation_t cublas_trans(char trans){ return (trans == 'N') ? CUBLAS_OP_N : ((trans == 'T') ? CUBLAS_OP_T : CUBLAS_OP_C); } //! \brief Wrapper around sgeam(). void geam(cublasHandle_t handle, cublasOperation_t transa, cublasOperation_t transb, int m, int n, float alpha, float const A[], int lda, float beta, float const B[], int ldb, float C[], int ldc){ cucheck(cublasSgeam(handle, transa, transb, m, n, &alpha, A, lda, &beta, B, ldb, C, ldc), "cublasSgeam()"); } //! \brief Wrapper around dgeam(). void geam(cublasHandle_t handle, cublasOperation_t transa, cublasOperation_t transb, int m, int n, double alpha, double const A[], int lda, double beta, double const B[], int ldb, double C[], int ldc){ cucheck(cublasDgeam(handle, transa, transb, m, n, &alpha, A, lda, &beta, B, ldb, C, ldc), "cublasDgeam()"); } //! \brief Wrapper around zgeam(). void geam(cublasHandle_t handle, cublasOperation_t transa, cublasOperation_t transb, int m, int n, std::complex alpha, std::complex const A[], int lda, std::complex beta, std::complex const B[], int ldb, std::complex C[], int ldc){ cucheck(cublasZgeam(handle, transa, transb, m, n, reinterpret_cast(&alpha), reinterpret_cast(A), lda, reinterpret_cast(&beta), reinterpret_cast(B), ldb, reinterpret_cast(C), ldc), "cublasZgeam()"); } //! \brief Wrapper around sgemv(). inline void gemv(cublasHandle_t handle, cublasOperation_t transa, int M, int N, float alpha, float const A[], int lda, float const x[], int incx, float beta, float y[], int incy){ cucheck( cublasSgemv(handle, transa, M, N, &alpha, A, lda, x, incx, &beta, y, incy), "cublasSgemv()"); } //! \brief Wrapper around dgemv(). inline void gemv(cublasHandle_t handle, cublasOperation_t transa, int M, int N, double alpha, double const A[], int lda, double const x[], int incx, double beta, double y[], int incy){ cucheck( cublasDgemv(handle, transa, M, N, &alpha, A, lda, x, incx, &beta, y, incy), "cublasDgemv()"); } //! \brief Wrapper around dtrsv(). inline void trsv(cublasHandle_t handle, cublasFillMode_t uplo, cublasOperation_t trans, cublasDiagType_t diag, int n, const double A[], int lda, double x[], int incx){ cucheck(cublasDtrsv(handle, uplo, trans, diag, n, A, lda, x, incx), "cublasDtrsv()"); } //! \brief Wrapper around ztrsv(). inline void trsv(cublasHandle_t handle, cublasFillMode_t uplo, cublasOperation_t trans, cublasDiagType_t diag, int n, const std::complex A[], int lda, std::complex x[], int incx){ cucheck(cublasZtrsv(handle, uplo, trans, diag, n, reinterpret_cast(A), lda, reinterpret_cast(x), incx), "cublasZtrsv()"); } //! \brief Wrapper around sgemm(). inline void gemm(cublasHandle_t handle, cublasOperation_t transa, cublasOperation_t transb, int M, int N, int K, float alpha, float const A[], int lda, float const B[], int ldb, float beta, float C[], int ldc){ cucheck( cublasSgemm(handle, transa, transb, M, N, K, &alpha, A, lda, B, ldb, &beta, C, ldc), "cublasSgemm()"); } //! \brief Wrapper around dgemm(). inline void gemm(cublasHandle_t handle, cublasOperation_t transa, cublasOperation_t transb, int M, int N, int K, double alpha, double const A[], int lda, double const B[], int ldb, double beta, double C[], int ldc){ cucheck( cublasDgemm(handle, transa, transb, M, N, K, &alpha, A, lda, B, ldb, &beta, C, ldc), "cublasDgemm()"); } //! \brief Wrapper around dtrsm(). inline void trsm(cublasHandle_t handle, cublasSideMode_t side, cublasFillMode_t uplo, cublasOperation_t trans, cublasDiagType_t diag, int m, int n, double alpha, double const A[], int lda, double B[], int ldb){ cucheck(cublasDtrsm(handle, side, uplo, trans, diag, m, n, &alpha, A, lda, B, ldb), "cublasDtrsm()"); } //! \brief Wrapper around ztrsm(). inline void trsm(cublasHandle_t handle, cublasSideMode_t side, cublasFillMode_t uplo, cublasOperation_t trans, cublasDiagType_t diag, int m, int n, std::complex alpha, std::complex const A[], int lda, std::complex B[], int ldb){ cucheck(cublasZtrsm(handle, side, uplo, trans, diag, m, n, reinterpret_cast(&alpha), reinterpret_cast(A), lda, reinterpret_cast(B), ldb), "cublasZtrsm()"); } /* * cuSparse section */ //! \brief Returns the buffer size needed by gemvi. template size_t size_sparse_gemvi(cusparseHandle_t handle, cusparseOperation_t transa, int M, int N, int nnz){ static_assert(std::is_same::value || std::is_same::value, "size_sparse_gemvi() works only with float and double"); int buff_size = 0; if (std::is_same::value){ cucheck( cusparseSgemvi_bufferSize(handle, transa, M, N, nnz, &buff_size), "cusparseSgemvi_bufferSize()"); }else{ cucheck( cusparseDgemvi_bufferSize(handle, transa, M, N, nnz, &buff_size), "cusparseDgemvi_bufferSize()"); } return static_cast(buff_size); } //! \brief Wrapper around sgemvi(). inline void sparse_gemvi(cusparseHandle_t handle, cusparseOperation_t transa, int M, int N, float alpha, float const A[], int lda, int nnz, const float x[], int const indx[], float beta, float y[]){ GpuVector buff(nullptr, size_sparse_gemvi(handle, transa, M, N, nnz) ); cucheck( cusparseSgemvi(handle, transa, M, N, &alpha, A, lda, nnz, x, indx, &beta, y, CUSPARSE_INDEX_BASE_ZERO, buff.data()), "cusparseSgemvi()"); } //! \brief Wrapper around dgemvi(). inline void sparse_gemvi(cusparseHandle_t handle, cusparseOperation_t transa, int M, int N, double alpha, double const A[], int lda, int nnz, const double x[], int const indx[], double beta, double y[]){ GpuVector buff(nullptr, size_sparse_gemvi(handle, transa, M, N, nnz) ); cucheck( cusparseDgemvi(handle, transa, M, N, &alpha, A, lda, nnz, x, indx, &beta, y, CUSPARSE_INDEX_BASE_ZERO, buff.data()), "cusparseDgemvi()"); } #if (CUDART_VERSION < 11000) //! \brief Wrapper around sgemv(). inline void sparse_gemv(cusparseHandle_t handle, cusparseOperation_t transa, int M, int N, int nnz, float alpha, cusparseMatDesc &matdesc, float const vals[], int const pntr[], int const indx[], float const x[], float beta, float y[]){ cucheck( cusparseScsrmv(handle, transa, M, N, nnz, &alpha, matdesc, vals, pntr, indx, x, &beta, y), "cusparseScsrmv()"); } //! \brief Wrapper around dgemv(). inline void sparse_gemv(cusparseHandle_t handle, cusparseOperation_t transa, int M, int N, int nnz, double alpha, cusparseMatDesc &matdesc, double const vals[], int const pntr[], int const indx[], double const x[], double beta, double y[]){ cucheck( cusparseDcsrmv(handle, transa, M, N, nnz, &alpha, matdesc, vals, pntr, indx, x, &beta, y), "cusparseDcsrmv()"); } //! \brief Wrapper around sgemm(). inline void sparse_gemm(cusparseHandle_t handle, cusparseOperation_t transa, cusparseOperation_t transb, int M, int N, int K, int nnz, float alpha, cusparseMatDesc &matdesc, float const vals[], int const pntr[], int const indx[], float const B[], int ldb, float beta, float C[], int ldc){ cucheck( cusparseScsrmm2(handle, transa, transb, M, N, K, nnz, &alpha, matdesc, vals, pntr, indx, B, ldb, &beta, C, ldc), "cusparseScsrmm2()"); } //! \brief Wrapper around dgemm(). inline void sparse_gemm(cusparseHandle_t handle, cusparseOperation_t transa, cusparseOperation_t transb, int M, int N, int K, int nnz, double alpha, cusparseMatDesc &matdesc, double const vals[], int const pntr[], int const indx[], double const B[], int ldb, double beta, double C[], int ldc){ cucheck( cusparseDcsrmm2(handle, transa, transb, M, N, K, nnz, &alpha, matdesc, vals, pntr, indx, B, ldb, &beta, C, ldc), "cusparseDcsrmm2()"); } #else //! \brief Wrapper around sgemv(). template inline void sparse_gemv(cusparseHandle_t handle, int M, int N, int nnz, typename GpuVector::value_type alpha, scalar_type const vals[], int const pntr[], int const indx[], scalar_type const x[], typename GpuVector::value_type beta, scalar_type y[]){ auto matdesc = makeSparseMatDesc(M, N, nnz, pntr, indx, vals); auto xdesc = makeSparseDenseVecDesc(N, x); auto ydesc = makeSparseDenseVecDesc(M, y); cudaDataType_t cuda_type = (std::is_same::value) ? CUDA_R_32F : CUDA_R_64F; size_t bsize = 0; #if (CUDART_VERSION < 12000) cucheck( cusparseSpMV_bufferSize(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matdesc, xdesc, &beta, ydesc, cuda_type, CUSPARSE_MV_ALG_DEFAULT, &bsize), "cusparseSpMV_bufferSize()" ); #else cucheck( cusparseSpMV_bufferSize(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matdesc, xdesc, &beta, ydesc, cuda_type, CUSPARSE_SPMV_ALG_DEFAULT, &bsize), "cusparseSpMV_bufferSize()" ); #endif GpuVector buffer(nullptr, bsize / sizeof(scalar_type)); #if (CUDART_VERSION < 12000) cucheck( cusparseSpMV(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matdesc, xdesc, &beta, ydesc, cuda_type, CUSPARSE_MV_ALG_DEFAULT, buffer.data()), "cusparseSpMV()" ); #else cucheck( cusparseSpMV(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matdesc, xdesc, &beta, ydesc, cuda_type, CUSPARSE_SPMV_ALG_DEFAULT, buffer.data()), "cusparseSpMV()" ); #endif } //! \brief Wrapper around dgemm(). template inline void sparse_gemm(cusparseHandle_t handle, int M, int N, int K, int nnz, typename GpuVector::value_type alpha, scalar_type const vals[], int const pntr[], int const indx[], scalar_type const B[], int ldb, typename GpuVector::value_type beta, scalar_type C[], int ldc){ auto matdesc = makeSparseMatDesc(M, K, nnz, pntr, indx, vals); auto bdesc = makeSparseDenseMatDesc(N, K, ldb, B); auto cdesc = makeSparseDenseMatDesc(M, N, ldc, C); cudaDataType_t cuda_type = (std::is_same::value) ? CUDA_R_32F : CUDA_R_64F; size_t bsize = 0; cucheck( cusparseSpMM_bufferSize(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, CUSPARSE_OPERATION_TRANSPOSE, &alpha, matdesc, bdesc, &beta, cdesc, cuda_type, CUSPARSE_SPMM_ALG_DEFAULT, &bsize), "cusparseSpMM_bufferSize()"); GpuVector buffer(nullptr, bsize / sizeof(scalar_type)); cucheck( cusparseSpMM(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, CUSPARSE_OPERATION_TRANSPOSE, &alpha, matdesc, bdesc, &beta, cdesc, cuda_type, CUSPARSE_SPMM_ALG_DEFAULT, buffer.data()), "cusparseSpMM()" ); } #endif /* * cuSolver section */ //! \brief Wrapper around dgeqrf() - get size. inline size_t size_geqrf(cusolverDnHandle_t handle, int m, int n, double A[], int lda){ int result = 0; cucheck(cusolverDnDgeqrf_bufferSize(handle, m, n, A, lda, &result), "cusolverDnDgeqrf_bufferSize()"); return static_cast(result); } //! \brief Wrapper around zgeqrf() - get size. inline size_t size_geqrf(cusolverDnHandle_t handle, int m, int n, std::complex A[], int lda){ int result = 0; cucheck(cusolverDnZgeqrf_bufferSize(handle, m, n, reinterpret_cast(A), lda, &result), "cusolverDnZgeqrf_bufferSize()"); return static_cast(result); } //! \brief Wrapper around dgeqrf(). inline void geqrf(cusolverDnHandle_t handle, int m, int n, double A[], int lda, double tau[]){ GpuVector workspace(nullptr, size_geqrf(handle, m, n, A, lda) ); GpuVector info(nullptr, std::vector(1, 0)); cucheck(cusolverDnDgeqrf(handle, m, n, A, lda, tau, workspace.data(), static_cast(workspace.size()), info.data()), "cusolverDnDgeqrf()"); if (info.unload(nullptr)[0] != 0) throw std::runtime_error("cusolverDnDgeqrf() returned non-zero status: " + std::to_string(info.unload(nullptr)[0])); } //! \brief Wrapper around zgeqrf(). inline void geqrf(cusolverDnHandle_t handle, int m, int n, std::complex A[], int lda, std::complex tau[]){ GpuVector> workspace( nullptr, size_geqrf(handle, m, n, A, lda) ); GpuVector info(nullptr, std::vector(1, 0)); cucheck(cusolverDnZgeqrf(handle, m, n, reinterpret_cast(A), lda, reinterpret_cast(tau), reinterpret_cast(workspace.data()), static_cast(workspace.size()), info.data()), "cusolverDnZgeqrf()"); if (info.unload(nullptr)[0] != 0) throw std::runtime_error("cusolverDnZgeqrf() returned non-zero status: " + std::to_string(info.unload(nullptr)[0])); } //! \brief Wrapper around dormqr() - get size. inline size_t size_gemqr(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, double const A[], int lda, double const tau[], double const C[], int ldc){ int result = 0; cucheck(cusolverDnDormqr_bufferSize(handle, side, trans, m, n, k, A, lda, tau, C, ldc, &result), "cusolverDnDormqr_bufferSize()"); return static_cast(result); } //! \brief Wrapper around zunmqr() - get size. inline size_t size_gemqr(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, std::complex const A[], int lda, std::complex const tau[], std::complex const C[], int ldc){ int result = 0; cucheck(cusolverDnZunmqr_bufferSize(handle, side, trans, m, n, k, reinterpret_cast(A), lda, reinterpret_cast(tau), reinterpret_cast(C), ldc, &result), "cusolverDnZunmqr_bufferSize()"); return static_cast(result); } //! \brief Wrapper around dormqr(). inline void gemqr(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, double const A[], int lda, double const tau[], double C[], int ldc){ GpuVector info(nullptr, std::vector(1, 0)); GpuVector workspace( nullptr, size_gemqr(handle, side, trans, m, n, k, A, lda, tau, C, ldc) ); cucheck(cusolverDnDormqr(handle, side, trans, m, n, k, A, lda, tau, C, ldc, workspace.data(), static_cast(workspace.size()), info.data()), "cusolverDnDormqr()"); if (info.unload(nullptr)[0] != 0) throw std::runtime_error("cusolverDnDormqr() returned non-zero status: " + std::to_string(info.unload(nullptr)[0])); } //! \brief Wrapper around zunmqr(). inline void gemqr(cusolverDnHandle_t handle, cublasSideMode_t side, cublasOperation_t trans, int m, int n, int k, std::complex const A[], int lda, std::complex const tau[], std::complex C[], int ldc){ GpuVector info(nullptr, std::vector(1, 0)); GpuVector> workspace( nullptr, size_gemqr(handle, side, trans, m, n, k, A, lda, tau, C, ldc) ); cucheck(cusolverDnZunmqr(handle, side, trans, m, n, k, reinterpret_cast(A), lda, reinterpret_cast(tau), reinterpret_cast(C), ldc, reinterpret_cast(workspace.data()), static_cast(workspace.size()), info.data()), "cusolverDnZunmqr()"); if (info.unload(nullptr)[0] != 0) throw std::runtime_error("cusolverDnZunmqr() returned non-zero status: " + std::to_string(info.unload(nullptr)[0])); } //! \brief Wrapper around cusolverDnDgetrs(). void getrs(cusolverDnHandle_t handle, cublasOperation_t trans, int n, int nrhs, double const A[], int lda, int const ipiv[], double B[], int ldb){ GpuVector info(nullptr, std::vector(1, 0)); cucheck(cusolverDnDgetrs(handle, trans, n, nrhs, A, lda, ipiv, B, ldb, info.data()), "cusolverDnDgetrs()"); if (info.unload(nullptr)[0] != 0) throw std::runtime_error("cusolverDnDgetrs() returned non-zero status: " + std::to_string(info.unload(nullptr)[0])); } //! \brief Wrapper around cusolverDnDgetrf(). void factorizePLU(AccelerationContext const *acceleration, int n, double A[], int ipiv[]){ cusolverDnHandle_t cusolverdnh = getCuSolverDnHandle(acceleration); int size = 0; cucheck(cusolverDnDgetrf_bufferSize(cusolverdnh, n, n, A, n, &size), "cusolverDnDgetrf_bufferSize()"); GpuVector workspace(nullptr, static_cast(size)); GpuVector info(nullptr, std::vector(1, 0)); cucheck(cusolverDnDgetrf(cusolverdnh, n, n, A, n, workspace.data(), ipiv, info.data()), "cusolverDnDgetrf()"); if (info.unload(nullptr)[0] != 0) throw std::runtime_error("cusolverDnDgetrf() returned non-zero status: " + std::to_string(info.unload(nullptr)[0])); } void solvePLU(AccelerationContext const *acceleration, char trans, int n, double const A[], int const ipiv[], double b[]){ cusolverDnHandle_t cusolverdnh = getCuSolverDnHandle(acceleration); getrs(cusolverdnh, (trans == 'T') ? CUBLAS_OP_T: CUBLAS_OP_N, n, 1, A, n, ipiv, b, n); } void solvePLU(AccelerationContext const *acceleration, char trans, int n, double const A[], int const ipiv[], int nrhs, double B[]){ cublasHandle_t cublash = getCuBlasHandle(acceleration); cusolverDnHandle_t cusolverdnh = getCuSolverDnHandle(acceleration); GpuVector BT(nullptr, n, nrhs); geam(cublash, CUBLAS_OP_T, CUBLAS_OP_T, n, nrhs, 1.0, B, nrhs, 0.0, B, nrhs, BT.data(), n); getrs(cusolverdnh, (trans == 'T') ? CUBLAS_OP_T: CUBLAS_OP_N, n, nrhs, A, n, ipiv, BT.data(), n); geam(cublash, CUBLAS_OP_T, CUBLAS_OP_T, nrhs, n, 1.0, BT.data(), n, 0.0, BT.data(), n, B, nrhs); } /* * Algorithm section */ template void solveLSmultiGPU(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]){ cublasHandle_t cublash = getCuBlasHandle(acceleration); cusolverDnHandle_t cusolverdnh = getCuSolverDnHandle(acceleration); GpuVector AT(nullptr, n, m); geam(cublash, CUBLAS_OP_T, CUBLAS_OP_T, n, m, 1.0, A, m, 0.0, A, m, AT.data(), n); GpuVector T(nullptr, m); geqrf(cusolverdnh, n, m, AT.data(), n, T.data()); cublasOperation_t trans = (std::is_same::value) ? CUBLAS_OP_T : CUBLAS_OP_C; if (nrhs == 1){ gemqr(cusolverdnh, CUBLAS_SIDE_LEFT, trans, n, 1, m, AT.data(), n, T.data(), B, n); trsv(cublash, CUBLAS_FILL_MODE_UPPER, CUBLAS_OP_N, CUBLAS_DIAG_NON_UNIT, m, AT.data(), n, B, 1); }else{ GpuVector BT(nullptr, n, nrhs); geam(cublash, CUBLAS_OP_T, CUBLAS_OP_T, n, nrhs, 1.0, B, nrhs, 0.0, B, nrhs, BT.data(), n); gemqr(cusolverdnh, CUBLAS_SIDE_LEFT, trans, n, nrhs, m, AT.data(), n, T.data(), BT.data(), n); trsm(cublash, CUBLAS_SIDE_LEFT, CUBLAS_FILL_MODE_UPPER, CUBLAS_OP_N, CUBLAS_DIAG_NON_UNIT, m, nrhs, 1.0, AT.data(), n, BT.data(), n); geam(cublash, CUBLAS_OP_T, CUBLAS_OP_T, nrhs, n, 1.0, BT.data(), n, 0.0, BT.data(), n, B, nrhs); } } template void solveLSmultiGPU(AccelerationContext const*, int, int, double[], int, double[]); template void solveLSmultiGPU>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); #ifndef Tasmanian_ENABLE_MAGMA template void solveLSmultiOOC(AccelerationContext const*, int, int, scalar_type[], int, scalar_type[]){} #endif template void solveLSmultiOOC(AccelerationContext const*, int, int, double[], int, double[]); template void solveLSmultiOOC>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); template void denseMultiply(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, GpuVector const &A, GpuVector const &B, typename GpuVector::value_type beta, scalar_type C[]){ cublasHandle_t cublash = getCuBlasHandle(acceleration); if (M > 1){ if (N > 1){ // matrix-matrix mode gemm(cublash, CUBLAS_OP_N, CUBLAS_OP_N, M, N, K, alpha, A.data(), M, B.data(), K, beta, C, M); }else{ // matrix vector, A * v = C gemv(cublash, CUBLAS_OP_N, M, K, alpha, A.data(), M, B.data(), 1, beta, C, 1); } }else{ // matrix vector B^T * v = C gemv(cublash, CUBLAS_OP_T, K, N, alpha, B.data(), K, A.data(), 1, beta, C, 1); } } template void denseMultiply(AccelerationContext const*, int, int, int, float, GpuVector const&, GpuVector const&, float, float[]); template void denseMultiply(AccelerationContext const*, int, int, int, double, GpuVector const&, GpuVector const&, double, double[]); #if (CUDART_VERSION < 11000) template void sparseMultiply(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, scalar_type C[]){ cusparseHandle_t cusparseh = getCuSparseHandle(acceleration); if (N > 1){ // dense matrix has many columns cusparseMatDesc matdesc; if (M > 1){ // dense matrix has many rows, use matrix-matrix algorithm GpuVector tempC(nullptr, M, N); sparse_gemm(cusparseh, CUSPARSE_OPERATION_NON_TRANSPOSE, CUSPARSE_OPERATION_TRANSPOSE, N, M, K, (int) indx.size(), alpha, matdesc, vals.data(), pntr.data(), indx.data(), A.data(), M, 0.0, tempC.data(), N); cublasHandle_t cublash = getCuBlasHandle(acceleration); geam(cublash, CUBLAS_OP_T, CUBLAS_OP_T, M, N, 1.0, tempC.data(), N, 0.0, tempC.data(), N, C, M); }else{ // dense matrix has only one row, use sparse matrix times dense vector sparse_gemv(cusparseh, CUSPARSE_OPERATION_NON_TRANSPOSE, N, K, (int) indx.size(), alpha, matdesc, vals.data(), pntr.data(), indx.data(), A.data(), 0.0, C); } }else{ // sparse matrix has only one column, use dense matrix times sparse vector // quote from Nvidia CUDA cusparse manual at https://docs.nvidia.com/cuda/cusparse/index.html#cusparse-lt-t-gt-gemvi // "This function requires no extra storage for the general matrices when operation CUSPARSE_OPERATION_NON_TRANSPOSE is selected." // Yet, buffer is required when num_nz exceeds 32 even with CUSPARSE_OPERATION_NON_TRANSPOSE sparse_gemvi(cusparseh, CUSPARSE_OPERATION_NON_TRANSPOSE, M, K, alpha, A.data(), M, (int) indx.size(), vals.data(), indx.data(), 0.0, C); } } #else template void sparseMultiply(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, scalar_type C[]){ cusparseHandle_t cusparseh = getCuSparseHandle(acceleration); if (N > 1){ // dense matrix has many columns if (M > 1){ // dense matrix has many rows, use matrix-matrix algorithm GpuVector tempC(nullptr, M, N); sparse_gemm(cusparseh, N, M, K, (int) indx.size(), alpha, vals.data(), pntr.data(), indx.data(), A.data(), M, 0.0, tempC.data(), N); cublasHandle_t cublash = getCuBlasHandle(acceleration); geam(cublash, CUBLAS_OP_T, CUBLAS_OP_T, M, N, 1.0, tempC.data(), N, 0.0, tempC.data(), N, C, M); }else{ // dense matrix has only one row, use sparse matrix times dense vector sparse_gemv(cusparseh, N, K, (int) indx.size(), alpha, vals.data(), pntr.data(), indx.data(), A.data(), 0.0, C); } }else{ sparse_gemvi(cusparseh, CUSPARSE_OPERATION_NON_TRANSPOSE, M, K, alpha, A.data(), M, (int) indx.size(), vals.data(), indx.data(), 0.0, C); } } #endif template void sparseMultiply(AccelerationContext const*, int, int, int, float, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, float C[]); template void sparseMultiply(AccelerationContext const*, int, int, int, double, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, double C[]); template void load_n(AccelerationContext const*, T const *cpu_data, size_t num_entries, T *gpu_data){ TasGpu::cucheck( cudaMemcpy(gpu_data, cpu_data, num_entries * sizeof(T), cudaMemcpyHostToDevice), "cudaMemcpy() load_n to device"); } template void load_n(AccelerationContext const*, int const*, size_t, int*); template void load_n(AccelerationContext const*, float const*, size_t, float*); template void load_n(AccelerationContext const*, double const*, size_t, double*); template void load_n>(AccelerationContext const*, std::complex const*, size_t, std::complex*); } } #endif TASMANIAN-8.1/InterfaceTPL/tsgCudaWrappers.hpp000066400000000000000000000276161470551176200210300ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_CUDA_WRAPPERS_HPP #define __TASMANIAN_CUDA_WRAPPERS_HPP #include "tsgGpuWrappers.hpp" #ifdef Tasmanian_ENABLE_CUDA #include #include #include #include #include #else #error "Cannot use tsgCudaWrappers.cpp without Tasmanian_ENABLE_CUDA" #endif #ifdef Tasmanian_ENABLE_MAGMA #include "tsgMagmaWrappers.hpp" #endif /*! * \file tsgCudaWrappers.hpp * \brief Wrappers to CUDA functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * Helper methods for the CUDA backend. */ namespace TasGrid{ namespace TasGpu{ /* * Common methods */ //! \brief Common error checking, prints a message based on the status and includes the \b info. inline void cucheck(cudaError_t status, std::string info){ if (status != cudaSuccess){ std::string message = "ERROR: cuda failed at "; message += info + " with error: "; message += cudaGetErrorString(status); throw std::runtime_error(message); } } //! \brief Common error checking, prints a message based on the status and includes the \b info. inline void cucheck(cublasStatus_t status, std::string info){ if (status != CUBLAS_STATUS_SUCCESS){ std::string message = "ERROR: cuBlas failed with code: "; if (status == CUBLAS_STATUS_NOT_INITIALIZED){ message += "CUBLAS_STATUS_NOT_INITIALIZED"; }else if (status == CUBLAS_STATUS_ALLOC_FAILED){ message += "CUBLAS_STATUS_ALLOC_FAILED"; }else if (status == CUBLAS_STATUS_INVALID_VALUE){ message += "CUBLAS_STATUS_INVALID_VALUE"; }else if (status == CUBLAS_STATUS_ARCH_MISMATCH){ message += "CUBLAS_STATUS_ARCH_MISMATCH"; }else if (status == CUBLAS_STATUS_MAPPING_ERROR){ message += "CUBLAS_STATUS_MAPPING_ERROR"; }else if (status == CUBLAS_STATUS_EXECUTION_FAILED){ message += "CUBLAS_STATUS_EXECUTION_FAILED"; }else if (status == CUBLAS_STATUS_INTERNAL_ERROR){ message += "CUBLAS_STATUS_INTERNAL_ERROR"; }else if (status == CUBLAS_STATUS_NOT_SUPPORTED){ message += "CUBLAS_STATUS_NOT_SUPPORTED"; }else if (status == CUBLAS_STATUS_LICENSE_ERROR){ message += "CUBLAS_STATUS_LICENSE_ERROR"; }else{ message += "UNKNOWN"; } message += " at "; message += info; throw std::runtime_error(message); } } //! \brief Common error checking, prints a message based on the status and includes the \b info. inline void cucheck(cusparseStatus_t status, std::string info){ if (status != CUSPARSE_STATUS_SUCCESS){ std::string message = "ERROR: cuSparse failed with code: "; if (status == CUSPARSE_STATUS_NOT_INITIALIZED){ message += "CUSPARSE_STATUS_NOT_INITIALIZED"; }else if (status == CUSPARSE_STATUS_ALLOC_FAILED){ message += "CUSPARSE_STATUS_ALLOC_FAILED"; }else if (status == CUSPARSE_STATUS_INVALID_VALUE){ message += "CUSPARSE_STATUS_INVALID_VALUE"; }else if (status == CUSPARSE_STATUS_ARCH_MISMATCH){ message += "CUSPARSE_STATUS_ARCH_MISMATCH"; }else if (status == CUSPARSE_STATUS_INTERNAL_ERROR){ message += "CUSPARSE_STATUS_INTERNAL_ERROR"; }else if (status == CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED){ message += "CUSPARSE_STATUS_MATRIX_TYPE_NOT_SUPPORTED"; }else if (status == CUSPARSE_STATUS_EXECUTION_FAILED){ message += "CUSPARSE_STATUS_EXECUTION_FAILED"; }else{ message += "UNKNOWN"; } message += " at "; message += info; throw std::runtime_error(message); } } //! \brief Common error checking, prints a message based on the status and includes the \b info. inline void cucheck(cusolverStatus_t status, std::string info){ if (status != CUSOLVER_STATUS_SUCCESS){ std::string message = "ERROR: cuSolver failed with error code " + std::to_string(status) + " at " + info; throw std::runtime_error(message); } } } namespace TasGpu{ //! \brief Make cuBlas handle. inline cublasHandle_t getCuBlasHandle(AccelerationContext const *acceleration){ if (not acceleration->engine->cublas_handle){ cublasHandle_t handle; cucheck( cublasCreate(&handle), "create handle" ); acceleration->engine->cublas_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter()); } return reinterpret_cast(acceleration->engine->cublas_handle.get()); } //! \brief Make cuSparse handle. inline cusparseHandle_t getCuSparseHandle(AccelerationContext const *acceleration){ if (not acceleration->engine->cusparse_handle){ cusparseHandle_t handle; cucheck( cusparseCreate(&handle), "create handle" ); acceleration->engine->cusparse_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter()); } return reinterpret_cast(acceleration->engine->cusparse_handle.get()); } //! \brief Wrapper around cusparseMatDescr_t struct cusparseMatDesc{ //! \brief An instance of cusparseMatDescr_t cusparseMatDescr_t mat_desc; //! \brief Create a general matrix description. cusparseMatDesc(){ cucheck( cusparseCreateMatDescr(&mat_desc), "cusparseCreateMatDescr()"); cusparseSetMatType(mat_desc, CUSPARSE_MATRIX_TYPE_GENERAL); cusparseSetMatIndexBase(mat_desc, CUSPARSE_INDEX_BASE_ZERO); cusparseSetMatDiagType(mat_desc, CUSPARSE_DIAG_TYPE_NON_UNIT); } //! \brief Use locally and internally, do not copy or move. cusparseMatDesc(cusparseMatDesc const&) = delete; //! \brief Release all used memory. ~cusparseMatDesc(){ cusparseDestroyMatDescr(mat_desc); } //! \brief Automatically convert to the wrapper description. operator cusparseMatDescr_t (){ return mat_desc; } }; #if (CUDART_VERSION >= 11000) template struct cusparseStructDescription{ //! \brief Construct a null description. cusparseStructDescription() : desc(nullptr){} //! \brief Destructor, deletes the description. ~cusparseStructDescription(){ if (std::is_same::value){ if (desc != nullptr) cusparseDestroySpMat(reinterpret_cast(desc)); }else if (std::is_same::value){ if (desc != nullptr) cusparseDestroyDnVec(reinterpret_cast(desc)); }else if (std::is_same::value){ if (desc != nullptr) cusparseDestroyDnMat(reinterpret_cast(desc)); } } //! \brief Move constructor. cusparseStructDescription(cusparseStructDescription &&other) : desc(other.desc){ other.desc = nullptr; } //! \brief Returns the description, automatic conversion. operator T () const{ return desc; } //! \brief Holds the description pointer. T desc; }; template cusparseStructDescription makeSparseMatDesc(int rows, int cols, int nnz, int const pntr[], int const indx[], scalar_type const vals[]){ cusparseStructDescription result; cudaDataType_t cuda_type = (std::is_same::value) ? CUDA_R_32F : CUDA_R_64F; cucheck( cusparseCreateCsr(&result.desc, (int64_t) rows, (int64_t) cols, (int64_t) nnz, const_cast(reinterpret_cast(pntr)), const_cast(reinterpret_cast(indx)), const_cast(reinterpret_cast(vals)), CUSPARSE_INDEX_32I, CUSPARSE_INDEX_32I, CUSPARSE_INDEX_BASE_ZERO, cuda_type), "cusparseCreateCsr()" ); return result; } template cusparseStructDescription makeSparseDenseVecDesc(int size, scalar_type const vals[]){ cusparseStructDescription result; cudaDataType_t cuda_type = (std::is_same::value) ? CUDA_R_32F : CUDA_R_64F; cucheck( cusparseCreateDnVec(&result.desc, static_cast(size), const_cast(reinterpret_cast(vals)), cuda_type), "cusparseCreateDnVec()" ); return result; } template cusparseStructDescription makeSparseDenseMatDesc(int rows, int cols, int lda, scalar_type const vals[]){ cusparseStructDescription result; cudaDataType_t cuda_type = (std::is_same::value) ? CUDA_R_32F : CUDA_R_64F; cucheck( cusparseCreateDnMat(&result.desc, static_cast(rows), static_cast(cols), static_cast(lda), const_cast(reinterpret_cast(vals)), cuda_type, CUSPARSE_ORDER_COL), "cusparseCreateDnMat()" ); return result; } #endif //! \brief Make cuSolver handle. inline cusolverDnHandle_t getCuSolverDnHandle(AccelerationContext const *acceleration){ if (not acceleration->engine->cusolver_handle){ cusolverDnHandle_t handle; cucheck( cusolverDnCreate(&handle), "create handle" ); acceleration->engine->cusolver_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter()); } return reinterpret_cast(acceleration->engine->cusolver_handle.get()); } } } #endif TASMANIAN-8.1/InterfaceTPL/tsgDpcppWrappers.cpp000066400000000000000000000445601470551176200212120ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DPCPP_WRAPPERS_CPP #define __TASMANIAN_DPCPP_WRAPPERS_CPP #include "tsgDpcppWrappers.hpp" /*! * \file tsgDpcppWrappers.cpp * \brief Wrappers to DPC++ functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * Realizations of the GPU algorithms using the DPC++/MKL backend. */ namespace TasGrid{ void InternalSyclQueue::init_testing(int gpuid){ use_testing = true; test_queue = makeNewQueue(gpuid); } InternalSyclQueue test_queue; template void GpuVector::resize(AccelerationContext const *acc, size_t count){ if (count != num_entries){ // if the current array is not big enoug clear(); // resets dynamic_mode num_entries = count; sycl::queue *q = getSyclQueue(acc); sycl_queue = reinterpret_cast(q); gpu_data = sycl::malloc_device(num_entries, *q); } } template void GpuVector::clear(){ num_entries = 0; if (gpu_data != nullptr){ sycl::queue *q = reinterpret_cast(sycl_queue); sycl::free(gpu_data, *q); q->wait(); // wait is needed here in case the pointer q gets deleted } gpu_data = nullptr; } template void GpuVector::load(AccelerationContext const *acc, size_t count, const T* cpu_data){ resize(acc, count); sycl::queue *q = getSyclQueue(acc); q->memcpy(gpu_data, cpu_data, count * sizeof(T)).wait(); } template void GpuVector::unload(AccelerationContext const *acc, size_t num, T* cpu_data) const{ sycl::queue *q = getSyclQueue(acc); q->memcpy(cpu_data, gpu_data, num * sizeof(T)).wait(); } template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const double*); template void GpuVector::unload(AccelerationContext const*, size_t, double*) const; template void GpuVector>::resize(AccelerationContext const*, size_t); template void GpuVector>::clear(); template void GpuVector>::load(AccelerationContext const*, size_t, const std::complex*); template void GpuVector>::unload(AccelerationContext const*, size_t, std::complex*) const; template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const float*); template void GpuVector::unload(AccelerationContext const*, size_t, float*) const; template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const int*); template void GpuVector::unload(AccelerationContext const*, size_t, int*) const; template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const std::int64_t*); template void GpuVector::unload(AccelerationContext const*, size_t, std::int64_t*) const; template<> void deleteHandle(int *p){ sycl::queue *q = reinterpret_cast(p); delete q; } void GpuEngine::setSyclQueue(void *queue){ internal_queue = std::unique_ptr> (reinterpret_cast(queue), HandleDeleter(false)); } int AccelerationMeta::getNumGpuDevices(){ return readSyclDevices().names.size(); } void AccelerationMeta::setDefaultGpuDevice(int){} unsigned long long AccelerationMeta::getTotalGPUMemory(int deviceID){ // int deviceID return readSyclDevices().memory[deviceID]; } std::string AccelerationMeta::getGpuDeviceName(int deviceID){ // int deviceID return readSyclDevices().names[deviceID]; } template void AccelerationMeta::recvGpuArray(AccelerationContext const *acc, size_t num_entries, const T *gpu_data, std::vector &cpu_data){ sycl::queue *q = getSyclQueue(acc); cpu_data.resize(num_entries); q->memcpy(cpu_data.data(), gpu_data, num_entries * sizeof(T)).wait(); } template void AccelerationMeta::delGpuArray(AccelerationContext const *acc, T *x){ sycl::queue *q = getSyclQueue(acc); sycl::free(x, *q); q->wait(); // wait is needed here in case the pointer q gets deleted } template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const double*, std::vector&); template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const float*, std::vector&); template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const int*, std::vector&); template void AccelerationMeta::delGpuArray(AccelerationContext const*, double*); template void AccelerationMeta::delGpuArray(AccelerationContext const*, float*); template void AccelerationMeta::delGpuArray(AccelerationContext const*, int*); namespace TasGpu{ template struct tsg_transpose{}; template void transpose_matrix(sycl::queue *q, int m, int n, scalar_type const A[], scalar_type AT[]){ q->submit([&](sycl::handler& h){ h.parallel_for>(sycl::range<2>{static_cast(m), static_cast(n)}, [=](sycl::id<2> i){ AT[i[0] * n + i[1]] = A[i[0] + m * i[1]]; }); }).wait(); } //! \brief Wrapper around rocsolver_dgetrf(). void factorizePLU(AccelerationContext const *acceleration, int n, double A[], int_gpu_lapack ipiv[]){ sycl::queue *q = getSyclQueue(acceleration); size_t size = oneapi::mkl::lapack::getrf_scratchpad_size(*q, n, n, n); GpuVector workspace(acceleration, size); oneapi::mkl::lapack::getrf(*q, n, n, A, n, ipiv, workspace.data(), size).wait(); } void solvePLU(AccelerationContext const *acceleration, char trans, int n, double const A[], int_gpu_lapack const ipiv[], double b[]){ sycl::queue *q = getSyclQueue(acceleration); size_t size = oneapi::mkl::lapack::getrs_scratchpad_size(*q, (trans == 'T') ? oneapi::mkl::transpose::T :oneapi::mkl::transpose::N, n, 1, n, n); GpuVector workspace(acceleration, size); oneapi::mkl::lapack::getrs(*q, (trans == 'T') ? oneapi::mkl::transpose::T :oneapi::mkl::transpose::N, n, 1, const_cast(A), n, const_cast(ipiv), b, n, workspace.data(), size).wait(); } void solvePLU(AccelerationContext const *acceleration, char trans, int n, double const A[], int_gpu_lapack const ipiv[], int nrhs, double B[]){ sycl::queue *q = getSyclQueue(acceleration); size_t size = oneapi::mkl::lapack::getrs_scratchpad_size(*q, (trans == 'T') ? oneapi::mkl::transpose::T :oneapi::mkl::transpose::N, n, nrhs, n, n); GpuVector workspace(acceleration, size); GpuVector BT(acceleration, n, nrhs); transpose_matrix(q, nrhs, n, B, BT.data()); oneapi::mkl::lapack::getrs(*q, (trans == 'T') ? oneapi::mkl::transpose::T :oneapi::mkl::transpose::N, n, nrhs, const_cast(A), n, const_cast(ipiv), BT.data(), n, workspace.data(), size).wait(); transpose_matrix(q, n, nrhs, BT.data(), B); } template void dump_data(sycl::queue *q, size_t m, size_t n, scalar_type *data){ std::vector cpu_data(m * n); q->memcpy(cpu_data.data(), data, Utils::size_mult(m, n) * sizeof(scalar_type)).wait(); std::cout << std::scientific; std::cout.precision(4); for(size_t i=0; i std::int64_t gemqr_workspace(cl::sycl::queue *q, oneapi::mkl::side side, oneapi::mkl::transpose trans, std::int64_t m, std::int64_t n, std::int64_t k, std::int64_t lda, std::int64_t ldc){ return oneapi::mkl::lapack::ormqr_scratchpad_size(*q, side, trans, m, n, k, lda, ldc); } template<> std::int64_t gemqr_workspace>(cl::sycl::queue *q, oneapi::mkl::side side, oneapi::mkl::transpose trans, std::int64_t m, std::int64_t n, std::int64_t k, std::int64_t lda, std::int64_t ldc){ return oneapi::mkl::lapack::unmqr_scratchpad_size>(*q, side, trans, m, n, k, lda, ldc); } template inline void gemqr(cl::sycl::queue *q, oneapi::mkl::side side, oneapi::mkl::transpose trans, std::int64_t m, std::int64_t n, std::int64_t k, scalar_type* A, std::int64_t lda, scalar_type *T, scalar_type* C, std::int64_t ldc, scalar_type* workspace, std::int64_t worksize){ oneapi::mkl::lapack::ormqr(*q, side, trans, m, n, k, A, lda, T, C, ldc, workspace, worksize).wait(); } template<> void gemqr>(cl::sycl::queue *q, oneapi::mkl::side side, oneapi::mkl::transpose trans, std::int64_t m, std::int64_t n, std::int64_t k, std::complex* A, std::int64_t lda, std::complex *T, std::complex* C, std::int64_t ldc, std::complex* workspace, std::int64_t worksize){ oneapi::mkl::lapack::unmqr(*q, side, trans, m, n, k, A, lda, T, C, ldc, workspace, worksize).wait(); } /* * Algorithm section */ template void solveLSmultiGPU(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]){ sycl::queue *q = getSyclQueue(acceleration); auto side = oneapi::mkl::side::left; auto trans = (std::is_same::value) ? oneapi::mkl::transpose::trans : oneapi::mkl::transpose::conjtrans; std::int64_t worksize = oneapi::mkl::lapack::geqrf_scratchpad_size(*q, n, m, n); worksize = std::max(worksize, gemqr_workspace(q, side, trans, n, nrhs, m, n, n)); GpuVector AT(acceleration, n, m); GpuVector T(acceleration, m); // tau parameter, or the weights of the orthogonal shift transpose_matrix(q, m, n, A, AT.data()); GpuVector workspace(acceleration, worksize); try{ oneapi::mkl::lapack::geqrf(*q, n, m, AT.data(), n, T.data(), workspace.data(), worksize).wait(); }catch(oneapi::mkl::lapack::exception &e){ std::cout << "lapack geqrf() error code: " << e.info() << "\nlapack geqrf() detail code: " << e.detail() << std::endl; throw; } if (nrhs == 1){ try{ gemqr(q, side, trans, n, 1, m, AT.data(), n, T.data(), B, n, workspace.data(), worksize); }catch(oneapi::mkl::lapack::exception &e){ std::cout << "lapack " << ((std::is_same::value) ? "ormqr()" : "unmqr()") << " error code: " << e.info() << "\nlapack " << ((std::is_same::value) ? "ormqr()" : "unmqr()") << " detail code: " << e.detail() << std::endl; throw; } oneapi::mkl::blas::column_major::trsv(*q, oneapi::mkl::uplo::U, oneapi::mkl::transpose::N, oneapi::mkl::diag::N, m, AT.data(), n, B, 1).wait(); }else{ GpuVector BT(acceleration, n, nrhs); transpose_matrix(q, nrhs, n, B, BT.data()); gemqr(q, side, trans, n, nrhs, m, AT.data(), n, T.data(), BT.data(), n, workspace.data(), worksize); oneapi::mkl::blas::column_major::trsm(*q, oneapi::mkl::side::L, oneapi::mkl::uplo::U, oneapi::mkl::transpose::N, oneapi::mkl::diag::N, m, nrhs, 1.0, AT.data(), n, BT.data(), n).wait(); transpose_matrix(q, n, nrhs, BT.data(), B); } } template void solveLSmultiGPU(AccelerationContext const*, int, int, double[], int, double[]); template void solveLSmultiGPU>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); #ifndef Tasmanian_ENABLE_MAGMA template void solveLSmultiOOC(AccelerationContext const*, int, int, scalar_type[], int, scalar_type[]){} #endif template void solveLSmultiOOC(AccelerationContext const*, int, int, double[], int, double[]); template void solveLSmultiOOC>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); template void denseMultiply(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, GpuVector const &A, GpuVector const &B, typename GpuVector::value_type beta, scalar_type C[]){ sycl::queue *q = getSyclQueue(acceleration); if (M > 1){ if (N > 1){ // matrix-matrix mode oneapi::mkl::blas::column_major::gemm(*q, oneapi::mkl::transpose::N, oneapi::mkl::transpose::N, M, N, K, alpha, A.data(), M, B.data(), K, beta, C, M).wait(); }else{ // matrix vector, A * v = C oneapi::mkl::blas::column_major::gemv(*q, oneapi::mkl::transpose::N, M, K, alpha, A.data(), M, B.data(), 1, beta, C, 1).wait(); } }else{ // matrix vector B^T * v = C oneapi::mkl::blas::column_major::gemv(*q, oneapi::mkl::transpose::T, K, N, alpha, B.data(), K, A.data(), 1, beta, C, 1).wait(); } } template void denseMultiply(AccelerationContext const*, int, int, int, float, GpuVector const&, GpuVector const&, float, float[]); template void denseMultiply(AccelerationContext const*, int, int, int, double, GpuVector const&, GpuVector const&, double, double[]); template void sparseMultiply(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, scalar_type C[]){ sycl::queue *q = getSyclQueue(acceleration); oneapi::mkl::sparse::matrix_handle_t mat = nullptr; oneapi::mkl::sparse::init_matrix_handle(&mat); oneapi::mkl::sparse::set_csr_data(*q, mat, N, K, oneapi::mkl::index_base::zero, const_cast(pntr.data()), const_cast(indx.data()), const_cast(vals.data())).wait(); if (M == 1){ // using sparse-blas level 2 oneapi::mkl::sparse::gemv(*q, oneapi::mkl::transpose::nontrans, alpha, mat, const_cast(A.data()), 0.0, C).wait(); }else{ // using sparse-blas level 3 oneapi::mkl::sparse::gemm(*q, oneapi::mkl::layout::row_major, oneapi::mkl::transpose::nontrans, oneapi::mkl::transpose::nontrans, alpha, mat, const_cast(A.data()), M, M, 0.0, C, M).wait(); } oneapi::mkl::sparse::release_matrix_handle(*q, &mat).wait(); } template void sparseMultiply(AccelerationContext const*, int, int, int, float, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, float C[]); template void sparseMultiply(AccelerationContext const*, int, int, int, double, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, double C[]); template void load_n(AccelerationContext const *acc, T const *cpu_data, size_t num_entries, T *gpu_data){ sycl::queue *q = getSyclQueue(acc); q->memcpy(gpu_data, cpu_data, num_entries * sizeof(T)).wait(); } template void load_n(AccelerationContext const*, int const*, size_t, int*); template void load_n(AccelerationContext const*, float const*, size_t, float*); template void load_n(AccelerationContext const*, double const*, size_t, double*); template void load_n>(AccelerationContext const*, std::complex const*, size_t, std::complex*); } } #endif TASMANIAN-8.1/InterfaceTPL/tsgDpcppWrappers.hpp000066400000000000000000000135011470551176200212060ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_DPCPP_WRAPPERS_HPP #define __TASMANIAN_DPCPP_WRAPPERS_HPP #include "tsgGpuWrappers.hpp" #ifndef Tasmanian_ENABLE_DPCPP #error "Cannot use tsgDpcppWrappers.cpp without Tasmanian_ENABLE_DPCPP" #endif #define MKL_INT int #include #include "oneapi/mkl.hpp" /*! * \file tsgDpcppWrappers.hpp * \brief Wrappers to DPC++ functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * Helper methods for the DPC++ backend. */ namespace TasGrid{ /*! * \internal * \ingroup TasmanianTPLWrappers * \brief Struct holding the names and memory capacity of each device. * * \endinternal */ struct tsg_device_list { //! \brief Device names. std::vector names; //! \brief Memory capacity. std::vector memory; }; /*! * \internal * \ingroup TasmanianTPLWrappers * \brief Creates a new tsg_gpu_selector and populates it with the names and memory for each device. * * \endinternal */ inline tsg_device_list readSyclDevices(){ tsg_device_list result; for(auto platform : sycl::platform::get_platforms()) { for(auto device : platform.get_devices()) { result.names.push_back(device.get_info()); result.memory.push_back(device.get_info()); } } return result; } /*! * \internal * \ingroup TasmanianTPLWrappers * \brief Return a new sycl::queue wrapped in a unique_ptr object in owning mode and associated with the given deviceID. * * \endinternal */ inline std::unique_ptr> makeNewQueue(int const deviceID){ if (deviceID == -1) { return std::unique_ptr>( reinterpret_cast( new sycl::queue( sycl::default_selector_v ) ), HandleDeleter() ); } int dcount = deviceID; for(auto platform : sycl::platform::get_platforms()) { for(auto device : platform.get_devices()) { if (dcount == 0) { return std::unique_ptr>( reinterpret_cast( new sycl::queue(device) ), HandleDeleter() ); } else { dcount--; } } } throw std::runtime_error("makeNewQueue() - Invalid deviceID = " + std::to_string(deviceID)); } /*! * \internal * \ingroup TasmanianTPLWrappers * \brief Returns the SYCL queue associated with the given AccelerationContext, creates a new queue if needed. * * If there is a current active sycl::queue the method will return a pointer to the queue, * otherwise tries to create a new sycl::queue using the sycl::gpu_selector. * If creating the GPU queue fails, e.g., throws sycl::exception, * then a queue will be created using the sycl::cpu_selector. * * \endinternal */ inline sycl::queue* getSyclQueue(AccelerationContext const *acceleration){ if (not acceleration->engine->internal_queue){ if (test_queue.use_testing){ acceleration->engine->internal_queue = test_queue; // take non-owning copy of the pointer }else{ acceleration->engine->internal_queue = makeNewQueue(acceleration->device); } } return reinterpret_cast(acceleration->engine->internal_queue.get()); } } #endif TASMANIAN-8.1/InterfaceTPL/tsgGpuNull.cpp000066400000000000000000000322701470551176200200010ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_CUDA_WRAPPERS_CPP #define __TASMANIAN_CUDA_WRAPPERS_CPP #include "tsgGpuWrappers.hpp" /*! * \file tsgGpuNull.cpp * \brief Wrappers to no-op functions with GPU signature. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * Reduces the need for preprocessor macros by providing methods with GPU signature but no-op implementation. */ namespace TasGrid{ /* * Meta methods */ template void GpuVector::resize(AccelerationContext const*, size_t){} template void GpuVector::clear(){} template void GpuVector::load(AccelerationContext const*, size_t, const T[]){} template void GpuVector::unload(AccelerationContext const*, size_t, T[]) const{} template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const double*); template void GpuVector::unload(AccelerationContext const*, size_t, double*) const; template void GpuVector>::resize(AccelerationContext const*, size_t); template void GpuVector>::clear(); template void GpuVector>::load(AccelerationContext const*, size_t, const std::complex*); template void GpuVector>::unload(AccelerationContext const*, size_t, std::complex*) const; template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const float*); template void GpuVector::unload(AccelerationContext const*, size_t, float*) const; template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const int*); template void GpuVector::unload(AccelerationContext const*, size_t, int*) const; int AccelerationMeta::getNumGpuDevices(){ return 0; } void AccelerationMeta::setDefaultGpuDevice(int){} unsigned long long AccelerationMeta::getTotalGPUMemory(int){ return 0; } std::string AccelerationMeta::getGpuDeviceName(int){ return std::string(); } template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t, const T[], std::vector&){} template void AccelerationMeta::delGpuArray(AccelerationContext const*, T*){} void* AccelerationMeta::createCublasHandle(){ return nullptr; } void AccelerationMeta::deleteCublasHandle(void*){} template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const double*, std::vector&); template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const float*, std::vector&); template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const int*, std::vector&); template void AccelerationMeta::delGpuArray(AccelerationContext const*, double*); template void AccelerationMeta::delGpuArray(AccelerationContext const*, float*); template void AccelerationMeta::delGpuArray(AccelerationContext const*, int*); namespace TasGpu{ /* * Algorithm section */ void factorizePLU(AccelerationContext const*, int, double[], int[]){} void solvePLU(AccelerationContext const*, char, int, double const[], int const[], double[]){} void solvePLU(AccelerationContext const*, char, int, double const[], int const[], int, double[]){} template void solveLSmultiGPU(AccelerationContext const*, int, int, scalar_type[], int, scalar_type[]){} template void solveLSmultiGPU(AccelerationContext const*, int, int, double[], int, double[]); template void solveLSmultiGPU>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); template void solveLSmultiOOC(AccelerationContext const*, int, int, scalar_type[], int, scalar_type[]){} template void solveLSmultiOOC(AccelerationContext const*, int, int, double[], int, double[]); template void solveLSmultiOOC>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); template void denseMultiply(AccelerationContext const*, int, int, int, typename GpuVector::value_type, GpuVector const&, GpuVector const&, typename GpuVector::value_type, scalar_type[]){} template void denseMultiply(AccelerationContext const*, int, int, int, float, GpuVector const&, GpuVector const&, float, float[]); template void denseMultiply(AccelerationContext const*, int, int, int, double, GpuVector const&, GpuVector const&, double, double[]); template void sparseMultiply(AccelerationContext const*, int, int, int, typename GpuVector::value_type, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, scalar_type[]){} template void sparseMultiply(AccelerationContext const*, int, int, int, float, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, float C[]); template void sparseMultiply(AccelerationContext const*, int, int, int, double, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, double C[]); template void dtrans2can(AccelerationContext const*, bool, int, int, int, double const[], double const[], T const[], T[]){} template void devalpwpoly(AccelerationContext const*, int, TypeOneDRule, int, int, int, const T[], const T[], const T[], T[]){} template void devalpwpoly_sparse(AccelerationContext const*, int, TypeOneDRule, int, int, const T[], GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector&, GpuVector&, GpuVector&){} template void devalseq(AccelerationContext const*, int, int, std::vector const&, T const[], GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, T[]){} template void devalfor(AccelerationContext const*, int, int, std::vector const&, const T[], GpuVector const&, GpuVector const&, T[], typename GpuVector::value_type[]){} template void devalglo(AccelerationContext const*, bool, bool, int, int, int, int, T const[], GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, T[]){} void fillDataGPU(AccelerationContext const*, double, long long, long long, double[]){} template void dtrans2can(AccelerationContext const*, bool, int, int, int, double const*, double const*, float const*, float*); template void dtrans2can(AccelerationContext const*, bool, int, int, int, double const*, double const*, double const*, double*); template void devalpwpoly(AccelerationContext const*, int, TypeOneDRule, int, int, int, float const*, float const*, float const*, float*); template void devalpwpoly(AccelerationContext const*, int, TypeOneDRule, int, int, int, double const*, double const*, double const*, double*); template void devalpwpoly_sparse(AccelerationContext const*, int, TypeOneDRule, int, int, float const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector&, GpuVector&, GpuVector&); template void devalpwpoly_sparse(AccelerationContext const*, int, TypeOneDRule, int, int, double const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector&, GpuVector&, GpuVector&); template void devalfor(AccelerationContext const*, int, int, std::vector const&, float const*, GpuVector const&, GpuVector const&, float*, float*); template void devalfor(AccelerationContext const*, int, int, std::vector const&, double const*, GpuVector const&, GpuVector const&, double*, double*); template void devalseq(AccelerationContext const*, int, int, std::vector const&, float const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, float*); template void devalseq(AccelerationContext const*, int, int, std::vector const&, double const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, double*); template void devalglo(AccelerationContext const*, bool, bool, int, int, int, int, float const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, float*); template void devalglo(AccelerationContext const*, bool, bool, int, int, int, int, double const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, double*); template void load_n(AccelerationContext const*, T const*, size_t, T*){} template void load_n(AccelerationContext const*, int const*, size_t, int*); template void load_n(AccelerationContext const*, float const*, size_t, float*); template void load_n(AccelerationContext const*, double const*, size_t, double*); template void load_n>(AccelerationContext const*, std::complex const*, size_t, std::complex*); } } #endif TASMANIAN-8.1/InterfaceTPL/tsgGpuWrappers.hpp000066400000000000000000000165271470551176200207060ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_GPU_WRAPPERS_HPP #define __TASMANIAN_GPU_WRAPPERS_HPP /*! * \internal * \file tsgGpuWrappers.hpp * \brief Wrappers to GPU functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * The header contains definitions of various operations that can be performed * on the GPU devices with the corresponding GPU backend. * \endinternal */ #include "tsgAcceleratedDataStructures.hpp" namespace TasGrid{ namespace TasGpu{ /*! * \brief Least squares solver with data sitting on the gpu device. * * Solves the least squares problem \f$ min_x \| A x - B \|^2_2 \f$ where \b A has \b n rows and \b m columns * (n >= m) and \b B has \b n rows and \b nrhs columns. Both matrices are stored in row-major format * on the GPU device associated with the given \b acceleration. * The matrix \b B will be overwritten with the solution. */ template void solveLSmultiGPU(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]); /*! * \brief Identical to TasGpu::solveLSmultiGPU() but the arrays are on the CPU and the MAGMA out-of-core implementation is used. */ template void solveLSmultiOOC(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]); //! \brief Identical to TasGpu::solveLSmultiGPU() but the data starts with the CPU and gets uploaded to the GPU first. template void solveLSmulti(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]){ GpuVector gpuA(acceleration, m, n, A); GpuVector gpuB(acceleration, nrhs, n, B); solveLSmultiGPU(acceleration, n, m, gpuA.data(), nrhs, gpuB.data()); gpuB.unload(acceleration, B); } //! \brief Factorize \f$ A = P L U \f$, arrays are on the GPU. void factorizePLU(AccelerationContext const *acceleration, int n, double A[], int_gpu_lapack ipiv[]); //! \brief Solve A x = b using a PLU factorization. void solvePLU(AccelerationContext const *acceleration, char trans, int n, double const A[], int_gpu_lapack const ipiv[], double b[]); //! \brief Solve A x = b using a PLU factorization, B is in row-major format. void solvePLU(AccelerationContext const *acceleration, char trans, int n, double const A[], int_gpu_lapack const ipiv[], int nrhs, double B[]); /*! * \brief Wrapper to GPU BLAS that multiplies dense matrices (e.g., cuBlas, MAGMA). * * Computes \f$ C = \alpha A B + \beta C \f$ where \b A is M by K, \b B is K by N, and \b C is M by N * all stored in column major format on the GPU device associated with the \b acceleration. * The signature is near identical to BLAS sgemm() or dgemm() but there are no transpose variants * and the leading dimensions are inferred as if the matrices have no padding. */ template void denseMultiply(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, GpuVector const &A, GpuVector const &B, typename GpuVector::value_type beta, scalar_type C[]); //! \brief Identical to TasGpu::denseMultiply() but both \b B and \b C are array in CPU memory. template void denseMultiplyMixed(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, GpuVector const &A, scalar_type const B[], typename GpuVector::value_type beta, scalar_type C[]){ GpuVector gpuB(acceleration, K, N, B), gpuC(acceleration, M, N); denseMultiply(acceleration, M, N, K, alpha, A, gpuB, beta, gpuC.data()); gpuC.unload(acceleration, C); } /*! * \brief Wrapper to GPU methods that multiplies a sparse and a dense matrix. * * Computes \f$ C = \alpha A B \f$ where \b A is M by K, \b B is K by N, and \b C is M by N, * matrices are in column major format with \b B being sparse in column compressed format. */ template void sparseMultiply(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, const GpuVector &A, const GpuVector &pntr, const GpuVector &indx, const GpuVector &vals, scalar_type C[]); //! \brief Identical to TasGpu::sparseMultiply() but the sparse matrix and the result \b C are in CPU memory. template void sparseMultiplyMixed(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, const GpuVector &A, const std::vector &pntr, const std::vector &indx, const std::vector &vals, T C[]){ GpuVector gpu_pntr(acceleration, pntr), gpu_indx(acceleration, indx); GpuVector gpu_vals(acceleration, vals), gpu_c(acceleration, M, N); sparseMultiply(acceleration, M, N, K, alpha, A, gpu_pntr, gpu_indx, gpu_vals, gpu_c.data()); gpu_c.unload(acceleration, C); } } } #endif TASMANIAN-8.1/InterfaceTPL/tsgHipWrappers.cpp000066400000000000000000000535671470551176200206730ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_CUDA_WRAPPERS_CPP #define __TASMANIAN_CUDA_WRAPPERS_CPP #include "tsgGpuWrappers.hpp" #include "tsgHipWrappers.hpp" /*! * \file tsgHipWrappers.cpp * \brief Wrappers to HIP functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * Realizations of the GPU algorithms using the HIP backend. */ namespace TasGrid{ /* * Meta methods */ template void GpuVector::resize(AccelerationContext const*, size_t count){ if (count != num_entries){ // if the current array is not big enough clear(); // resets dynamic_mode num_entries = count; TasGpu::hipcheck( hipMalloc((void**) &gpu_data, num_entries * sizeof(T)), "hipMalloc()"); } } template void GpuVector::clear(){ num_entries = 0; if (gpu_data != nullptr) // if I own the data and the data is not null TasGpu::hipcheck( hipFree(gpu_data), "hipFree()"); gpu_data = nullptr; } template void GpuVector::load(AccelerationContext const*, size_t count, const T* cpu_data){ resize(nullptr, count); TasGpu::hipcheck( hipMemcpy(gpu_data, cpu_data, num_entries * sizeof(T), hipMemcpyHostToDevice), "hipMemcpy() to device"); } template void GpuVector::unload(AccelerationContext const*, size_t num, T* cpu_data) const{ TasGpu::hipcheck( hipMemcpy(cpu_data, gpu_data, num * sizeof(T), hipMemcpyDeviceToHost), "hipMemcpy() from device"); } template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const double*); template void GpuVector::unload(AccelerationContext const*, size_t, double*) const; template void GpuVector>::resize(AccelerationContext const*, size_t); template void GpuVector>::clear(); template void GpuVector>::load(AccelerationContext const*, size_t, const std::complex*); template void GpuVector>::unload(AccelerationContext const*, size_t, std::complex*) const; template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const float*); template void GpuVector::unload(AccelerationContext const*, size_t, float*) const; template void GpuVector::resize(AccelerationContext const*, size_t); template void GpuVector::clear(); template void GpuVector::load(AccelerationContext const*, size_t, const int*); template void GpuVector::unload(AccelerationContext const*, size_t, int*) const; template<> void deleteHandle(int *p){ rocblas_destroy_handle(reinterpret_cast(p)); } template<> void deleteHandle(int *p){ rocsparse_destroy_handle(reinterpret_cast(p)); } void GpuEngine::setRocBlasHandle(void *handle){ rblas_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter(false)); } void GpuEngine::setRocSparseHandle(void *handle){ rsparse_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter(false)); } int AccelerationMeta::getNumGpuDevices(){ int gpu_count = 0; TasGpu::hipcheck( hipGetDeviceCount(&gpu_count), "hipGetDeviceCount()"); return gpu_count; } void AccelerationMeta::setDefaultGpuDevice(int deviceID){ TasGpu::hipcheck( hipSetDevice(deviceID), "hipSetDevice()"); } unsigned long long AccelerationMeta::getTotalGPUMemory(int deviceID){ // int deviceID hipDeviceProp_t prop; TasGpu::hipcheck( hipGetDeviceProperties(&prop, deviceID), "hipGetDeviceProperties()"); return prop.totalGlobalMem; } std::string AccelerationMeta::getGpuDeviceName(int deviceID){ // int deviceID if ((deviceID < 0) || (deviceID >= getNumGpuDevices())) return std::string(); hipDeviceProp_t prop; TasGpu::hipcheck( hipGetDeviceProperties(&prop, deviceID), "hipGetDeviceProperties()"); return std::string(prop.name); } template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const T *gpu_data, std::vector &cpu_data){ cpu_data.resize(num_entries); TasGpu::hipcheck( hipMemcpy(cpu_data.data(), gpu_data, num_entries * sizeof(T), hipMemcpyDeviceToHost), "hip receive"); } template void AccelerationMeta::delGpuArray(AccelerationContext const*, T *x){ TasGpu::hipcheck( hipFree(x), "hipFree()"); } template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const double*, std::vector&); template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const float*, std::vector&); template void AccelerationMeta::recvGpuArray(AccelerationContext const*, size_t num_entries, const int*, std::vector&); template void AccelerationMeta::delGpuArray(AccelerationContext const*, double*); template void AccelerationMeta::delGpuArray(AccelerationContext const*, float*); template void AccelerationMeta::delGpuArray(AccelerationContext const*, int*); namespace TasGpu{ /* * rocBLAS section */ //! \brief Converts character to cublas operation. constexpr rocblas_operation cublas_trans(char trans){ return (trans == 'N') ? rocblas_operation_none : ((trans == 'T') ? rocblas_operation_transpose : rocblas_operation_conjugate_transpose); } //! \brief Wrapper around sgeam(). void geam(rocblas_handle handle, rocblas_operation transa, rocblas_operation transb, int m, int n, float alpha, float const A[], int lda, float beta, float const B[], int ldb, float C[], int ldc){ hipcheck(rocblas_sgeam(handle, transa, transb, m, n, &alpha, A, lda, &beta, B, ldb, C, ldc), "cublasSgeam()"); } //! \brief Wrapper around dgeam(). void geam(rocblas_handle handle, rocblas_operation transa, rocblas_operation transb, int m, int n, double alpha, double const A[], int lda, double beta, double const B[], int ldb, double C[], int ldc){ hipcheck(rocblas_dgeam(handle, transa, transb, m, n, &alpha, A, lda, &beta, B, ldb, C, ldc), "cublasDgeam()"); } //! \brief Wrapper around sgemv(). inline void gemv(rocblas_handle handle, rocblas_operation transa, int M, int N, float alpha, float const A[], int lda, float const x[], int incx, float beta, float y[], int incy){ hipcheck( rocblas_sgemv(handle, transa, M, N, &alpha, A, lda, x, incx, &beta, y, incy), "rocblas_sgemv()"); } //! \brief Wrapper around dgemv(). inline void gemv(rocblas_handle handle, rocblas_operation transa, int M, int N, double alpha, double const A[], int lda, double const x[], int incx, double beta, double y[], int incy){ hipcheck( rocblas_dgemv(handle, transa, M, N, &alpha, A, lda, x, incx, &beta, y, incy), "rocblas_sgemv()"); } //! \brief Wrapper around sgemm(). inline void gemm(rocblas_handle handle, rocblas_operation transa, rocblas_operation transb, int M, int N, int K, float alpha, float const A[], int lda, float const B[], int ldb, float beta, float C[], int ldc){ hipcheck( rocblas_sgemm(handle, transa, transb, M, N, K, &alpha, A, lda, B, ldb, &beta, C, ldc), "rocblas_sgemm()"); } //! \brief Wrapper around dgemm(). inline void gemm(rocblas_handle handle, rocblas_operation transa, rocblas_operation transb, int M, int N, int K, double alpha, double const A[], int lda, double const B[], int ldb, double beta, double C[], int ldc){ hipcheck( rocblas_dgemm(handle, transa, transb, M, N, K, &alpha, A, lda, B, ldb, &beta, C, ldc), "rocblas_dgemm()"); } //! \brief Wrapper around dtrsm(). inline void trsm(rocblas_handle handle, rocblas_side side, rocblas_fill uplo, rocblas_operation trans, rocblas_diagonal diag, int m, int n, double alpha, double const A[], int lda, double B[], int ldb){ hipcheck(rocblas_dtrsm(handle, side, uplo, trans, diag, m, n, &alpha, A, lda, B, ldb), "rocblas_dtrsm()"); } //! \brief Wrapper around ztrsm(). inline void trsm(rocblas_handle handle, rocblas_side side, rocblas_fill uplo, rocblas_operation trans, rocblas_diagonal diag, int m, int n, std::complex alpha, std::complex const A[], int lda, std::complex B[], int ldb){ hipcheck(rocblas_ztrsm(handle, side, uplo, trans, diag, m, n, reinterpret_cast(&alpha), reinterpret_cast(A), lda, reinterpret_cast(B), ldb), "rocblas_ztrsm()"); } /* * rocSparse section */ inline void sparse_gemv(rocsparse_handle handle, rocsparse_operation trans, int M, int N, int nnz, float alpha, float const vals[], int const pntr[], int const indx[], float const x[], float beta, float y[]){ rocsparseMatDesc desc; rocsparseMatInfo info; hipcheck( rocsparse_scsrmv_analysis(handle, trans, M, N, nnz, desc, vals, pntr, indx, info), "sgemv-info"); hipcheck( rocsparse_scsrmv(handle, trans, M, N, nnz, &alpha, desc, vals, pntr, indx, info, x, &beta, y), "sgemv"); } inline void sparse_gemv(rocsparse_handle handle, rocsparse_operation trans, int M, int N, int nnz, double alpha, double const vals[], int const pntr[], int const indx[], double const x[], double beta, double y[]){ rocsparseMatDesc desc; rocsparseMatInfo info; hipcheck( rocsparse_dcsrmv_analysis(handle, trans, M, N, nnz, desc, vals, pntr, indx, info), "dgemv-info"); hipcheck( rocsparse_dcsrmv(handle, trans, M, N, nnz, &alpha, desc, vals, pntr, indx, info, x, &beta, y), "dgemv"); } //! \brief Wrapper around dgemm(). inline void sparse_gemm(rocsparse_handle handle, rocsparse_operation transa, rocsparse_operation transb, int M, int N, int K, int nnz, float alpha, float const vals[], int const pntr[], int const indx[], float const B[], int ldb, float beta, float C[], int ldc){ rocsparseMatDesc desc; hipcheck( rocsparse_scsrmm(handle, transa, transb, M, N, K, nnz, &alpha, desc, vals, pntr, indx, B, ldb, &beta, C, ldc), "dgemm()"); } //! \brief Wrapper around rocsparse_dcsrmm(). inline void sparse_gemm(rocsparse_handle handle, rocsparse_operation transa, rocsparse_operation transb, int M, int N, int K, int nnz, double alpha, double const vals[], int const pntr[], int const indx[], double const B[], int ldb, double beta, double C[], int ldc){ rocsparseMatDesc desc; hipcheck( rocsparse_dcsrmm(handle, transa, transb, M, N, K, nnz, &alpha, desc, vals, pntr, indx, B, ldb, &beta, C, ldc), "dgemm()"); } /* * rocSolver section */ //! \brief Wrapper around rocsolver_dgetrs(). void getrs(rocblas_handle handle, rocblas_operation trans, int n, int nrhs, double const A[], int lda, int const ipiv[], double B[], int ldb){ hipcheck(rocblas_set_pointer_mode(handle, rocblas_pointer_mode_device), "rocblas_set_pointer_mode()"); hipcheck(rocsolver_dgetrs(handle, trans, n, nrhs, const_cast(A), lda, ipiv, B, ldb), "rocsolver_dgetrs()"); rocblas_set_pointer_mode(handle, rocblas_pointer_mode_host); } //! \brief Wrapper around rocsolver_dgetrf(). void factorizePLU(AccelerationContext const *acceleration, int n, double A[], int ipiv[]){ rocblas_handle rochandle = getRocBlasHandle(acceleration); GpuVector info(acceleration, std::vector(4, 0)); hipcheck(rocblas_set_pointer_mode(rochandle, rocblas_pointer_mode_device), "rocblas_set_pointer_mode()"); hipcheck(rocsolver_dgetrf(rochandle, n, n, A, n, ipiv, info.data()), "rocsolver_dgetrf()"); rocblas_set_pointer_mode(rochandle, rocblas_pointer_mode_host); if (info.unload(nullptr)[0] != 0) throw std::runtime_error("rocsolver_dgetrf() returned non-zero status: " + std::to_string(info.unload(nullptr)[0])); } void solvePLU(AccelerationContext const *acceleration, char trans, int n, double const A[], int const ipiv[], double b[]){ rocblas_handle rochandle = getRocBlasHandle(acceleration); getrs(rochandle, (trans == 'T') ? rocblas_operation_transpose: rocblas_operation_none, n, 1, A, n, ipiv, b, n); } void solvePLU(AccelerationContext const *acceleration, char trans, int n, double const A[], int const ipiv[], int nrhs, double B[]){ rocblas_handle rochandle = getRocBlasHandle(acceleration); GpuVector BT(nullptr, n, nrhs); geam(rochandle, rocblas_operation_transpose, rocblas_operation_transpose, n, nrhs, 1.0, B, nrhs, 0.0, B, nrhs, BT.data(), n); getrs(rochandle, (trans == 'T') ? rocblas_operation_transpose: rocblas_operation_none, n, nrhs, A, n, ipiv, BT.data(), n); geam(rochandle, rocblas_operation_transpose, rocblas_operation_transpose, nrhs, n, 1.0, BT.data(), n, 0.0, BT.data(), n, B, nrhs); } //! \brief Wrapper around rocsolver_dgelqf(). inline void gelqf(rocblas_handle handle, int m, int n, double A[], double tau[]){ hipcheck(rocsolver_dgelqf(handle, m, n, A, m, tau), "rocsolver_dgelqf()"); } //! \brief Wrapper around rocsolver_zgelqf(). inline void gelqf(rocblas_handle handle, int m, int n, std::complex A[], std::complex tau[]){ hipcheck(rocsolver_zgelqf(handle, m, n, reinterpret_cast(A), m, reinterpret_cast(tau)), "rocsolver_zgelqf()"); } //! \brief Wrapper around rocsolver_dormlq(), does Q^T times C. inline void gemlq(rocblas_handle handle, int m, int n, int k, double A[], double tau[], double C[]){ hipcheck(rocsolver_dormlq(handle, rocblas_side_right, rocblas_operation_transpose, m, n, k, A, k, tau, C, m), "rocsolver_dormlq()"); } //! \brief Wrapper around rocsolver_dunmlq(), does Q^T times C. inline void gemlq(rocblas_handle handle, int m, int n, int k, std::complex A[], std::complex tau[], std::complex C[]){ hipcheck(rocsolver_zunmlq(handle, rocblas_side_right, rocblas_operation_conjugate_transpose, m, n, k, reinterpret_cast(A), k, reinterpret_cast(tau), reinterpret_cast(C), m), "rocsolver_zunmlq()"); } /* * Algorithm section */ template void solveLSmultiGPU(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]){ rocblas_handle rochandle = getRocBlasHandle(acceleration); GpuVector tau(acceleration, std::min(n, m)); gelqf(rochandle, m, n, A, tau.data()); gemlq(rochandle, nrhs, n, m, A, tau.data(), B); trsm(rochandle, rocblas_side_right, rocblas_fill_lower, rocblas_operation_none, rocblas_diagonal_non_unit, nrhs, m, 1.0, A, m, B, nrhs); } template void solveLSmultiGPU(AccelerationContext const*, int, int, double[], int, double[]); template void solveLSmultiGPU>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); #ifndef Tasmanian_ENABLE_MAGMA template void solveLSmultiOOC(AccelerationContext const*, int, int, scalar_type[], int, scalar_type[]){} #endif template void solveLSmultiOOC(AccelerationContext const*, int, int, double[], int, double[]); template void solveLSmultiOOC>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); template void denseMultiply(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, GpuVector const &A, GpuVector const &B, typename GpuVector::value_type beta, scalar_type C[]){ rocblas_handle cublash = getRocBlasHandle(acceleration); if (M > 1){ if (N > 1){ // matrix-matrix mode gemm(cublash, rocblas_operation_none, rocblas_operation_none, M, N, K, alpha, A.data(), M, B.data(), K, beta, C, M); }else{ // matrix vector, A * v = C gemv(cublash, rocblas_operation_none, M, K, alpha, A.data(), M, B.data(), 1, beta, C, 1); } }else{ // matrix vector B^T * v = C gemv(cublash, rocblas_operation_transpose, K, N, alpha, B.data(), K, A.data(), 1, beta, C, 1); } } template void denseMultiply(AccelerationContext const*, int, int, int, float, GpuVector const&, GpuVector const&, float, float[]); template void denseMultiply(AccelerationContext const*, int, int, int, double, GpuVector const&, GpuVector const&, double, double[]); template void sparseMultiply(AccelerationContext const *acceleration, int M, int N, int K, typename GpuVector::value_type alpha, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, scalar_type C[]){ rocsparse_handle rocsparseh = getRocSparseHandle(acceleration); if (N > 1){ if (M > 1){ GpuVector tempC(nullptr, M, N); sparse_gemm(rocsparseh, rocsparse_operation_none, rocsparse_operation_transpose, N, M, K, static_cast(indx.size()), alpha, vals.data(), pntr.data(), indx.data(), A.data(), M, 0.0, tempC.data(), N); rocblas_handle rocblash = getRocBlasHandle(acceleration); geam(rocblash, rocblas_operation_transpose, rocblas_operation_transpose, M, N, 1.0, tempC.data(), N, 0.0, tempC.data(), N, C, M); }else{ sparse_gemv(rocsparseh, rocsparse_operation_none, N, K, static_cast(indx.size()), alpha, vals.data(), pntr.data(), indx.data(), A.data(), 0.0, C); } }else{ GpuVector tempC(nullptr, M, N); int nnz = static_cast(indx.size()); GpuVector temp_pntr(nullptr, std::vector{0, nnz}); sparse_gemm(rocsparseh, rocsparse_operation_none, rocsparse_operation_transpose, N, M, K, nnz, alpha, vals.data(), temp_pntr.data(), indx.data(), A.data(), M, 0.0, tempC.data(), N); rocblas_handle rocblash = getRocBlasHandle(acceleration); geam(rocblash, rocblas_operation_transpose, rocblas_operation_transpose, M, N, 1.0, tempC.data(), N, 0.0, tempC.data(), N, C, M); } } template void sparseMultiply(AccelerationContext const*, int, int, int, float, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, float C[]); template void sparseMultiply(AccelerationContext const*, int, int, int, double, GpuVector const &A, GpuVector const &pntr, GpuVector const &indx, GpuVector const &vals, double C[]); template void load_n(AccelerationContext const*, T const *cpu_data, size_t num_entries, T *gpu_data){ TasGpu::hipcheck( hipMemcpy(gpu_data, cpu_data, num_entries * sizeof(T), hipMemcpyHostToDevice), "hipMemcpy() load_n to device"); } template void load_n(AccelerationContext const*, int const*, size_t, int*); template void load_n(AccelerationContext const*, float const*, size_t, float*); template void load_n(AccelerationContext const*, double const*, size_t, double*); template void load_n>(AccelerationContext const*, std::complex const*, size_t, std::complex*); } } #endif TASMANIAN-8.1/InterfaceTPL/tsgHipWrappers.hpp000066400000000000000000000207561470551176200206720ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_HIP_WRAPPERS_HPP #define __TASMANIAN_HIP_WRAPPERS_HPP #include "tsgGpuWrappers.hpp" #ifndef Tasmanian_ENABLE_HIP #error "Cannot use tsgHipWrappers.cpp without Tasmanian_ENABLE_HIP" #endif #ifndef __HIP_PLATFORM_HCC__ #define __HIP_PLATFORM_HCC__ #endif #include #include #include #include #ifdef Tasmanian_ENABLE_MAGMA #define HAVE_HIP #include "tsgMagmaWrappers.hpp" #endif /*! * \file tsgHipWrappers.hpp * \brief Wrappers to HIP functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * Helper methods for the HIP backend. */ namespace TasGrid{ namespace TasGpu{ /* * Common methods */ inline void hipcheck(hipError_t status, std::string info){ if (status != hipSuccess) throw std::runtime_error(std::string("rocm-hip encountered an error with code: ") + std::to_string(status) + " at " + info); } inline std::string hip_info_from(rocblas_status status){ switch(status){ case rocblas_status_success : return "success"; case rocblas_status_invalid_handle : return "invlida handle"; case rocblas_status_not_implemented : return "not implemented"; case rocblas_status_invalid_pointer : return "invalid pointer"; case rocblas_status_invalid_size : return "invalid size"; case rocblas_status_memory_error : return "memory error"; case rocblas_status_internal_error : return "internal error"; case rocblas_status_perf_degraded : return "performance degraded due to low memory"; case rocblas_status_size_query_mismatch : return "unmatched start/stop size query"; case rocblas_status_size_increased : return "queried device memory size increased"; case rocblas_status_size_unchanged : return "queried device memory size unchanged"; case rocblas_status_invalid_value : return "passed argument not valid"; case rocblas_status_continue : return "nothing preventing function to proceed"; default: return "unknown"; } } inline std::string hip_info_from(rocsparse_status status){ switch(status){ case rocsparse_status_success : return "success"; case rocsparse_status_invalid_handle : return "invlida handle"; case rocsparse_status_not_implemented : return "not implemented"; case rocsparse_status_invalid_pointer : return "invalid pointer"; case rocsparse_status_invalid_size : return "invalid size"; case rocsparse_status_memory_error : return "memory error"; case rocsparse_status_internal_error : return "internal error"; case rocsparse_status_invalid_value : return "passed argument not valid"; case rocsparse_status_arch_mismatch : return "architecture mismatch"; case rocsparse_status_zero_pivot : return "zero pivot"; default: return "unknown"; } } inline void hipcheck(rocblas_status status, std::string info){ if (status != rocblas_status_success) throw std::runtime_error(std::string("rocblas encountered an error with code: ") + hip_info_from(status) + ", at " + info); } inline void hipcheck(rocsparse_status status, std::string info){ if (status != rocsparse_status_success) throw std::runtime_error(std::string("rocsparse encountered an error with code: ") + hip_info_from(status) + ", at " + info); } //! \brief Make rocBlas handle. inline rocblas_handle getRocBlasHandle(AccelerationContext const *acceleration){ if (not acceleration->engine->rblas_handle){ rocblas_handle handle; hipcheck( rocblas_create_handle(&handle), "create handle" ); acceleration->engine->rblas_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter()); } return reinterpret_cast(acceleration->engine->rblas_handle.get()); } //! \brief Make rocSparse handle. inline rocsparse_handle getRocSparseHandle(AccelerationContext const *acceleration){ if (not acceleration->engine->rsparse_handle){ rocsparse_handle handle; hipcheck( rocsparse_create_handle(&handle), "create handle" ); acceleration->engine->rsparse_handle = std::unique_ptr> (reinterpret_cast(handle), HandleDeleter()); } return reinterpret_cast(acceleration->engine->rsparse_handle.get()); } //! \brief Wrapper around rocsparse_mat_descr struct rocsparseMatDesc{ //! \brief An instance of rocsparse_mat_descr rocsparse_mat_descr mat_desc; //! \brief Create a general matrix description. rocsparseMatDesc(){ hipcheck( rocsparse_create_mat_descr(&mat_desc), "rocsparse_create_mat_descr()"); rocsparse_set_mat_type(mat_desc, rocsparse_matrix_type_general); rocsparse_set_mat_index_base(mat_desc, rocsparse_index_base_zero); rocsparse_set_mat_diag_type(mat_desc, rocsparse_diag_type_non_unit); } //! \brief Use locally and internally, do not copy or move. rocsparseMatDesc(rocsparseMatDesc const&) = delete; //! \brief Release all used memory. ~rocsparseMatDesc(){ rocsparse_destroy_mat_descr(mat_desc); } //! \brief Automatically convert to the wrapper description. operator rocsparse_mat_descr (){ return mat_desc; } }; //! \brief Wrapper around rocsparse_mat_info struct rocsparseMatInfo{ //! \brief An instance of rocsparse_mat_info rocsparse_mat_info mat_info; //! \brief Create a general matrix description. rocsparseMatInfo(){ hipcheck( rocsparse_create_mat_info(&mat_info), "rocsparse_create_mat_info()"); } //! \brief Use locally and internally, do not copy or move. rocsparseMatInfo(rocsparseMatInfo const&) = delete; //! \brief Move constructor is allowed rocsparseMatInfo(rocsparseMatInfo &&other) : mat_info(Utils::exchange(other.mat_info, nullptr)){} //! \brief Release all used memory. ~rocsparseMatInfo(){ if (mat_info != nullptr) rocsparse_destroy_mat_info(mat_info); } //! \brief Automatically convert to the wrapper description. operator rocsparse_mat_info (){ return mat_info; } }; } } #endif TASMANIAN-8.1/InterfaceTPL/tsgMagmaWrappers.hpp000066400000000000000000000207211470551176200211640ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_MAGMA_WRAPPERS_HPP #define __TASMANIAN_MAGMA_WRAPPERS_HPP #include "tsgGpuWrappers.hpp" #ifdef Tasmanian_ENABLE_MAGMA #include "magma_v2.h" #else #error "Cannot use tsgMagmaWrappers.hpp without Tasmanian_ENABLE_MAGMA" #endif /*! * \file tsgMagmaWrappers.cpp * \brief Wrappers to CUDA functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * Realizations of the GPU algorithms using the CUDA backend. */ namespace TasGrid{ namespace TasGpu{ //! \brief Calls magma_init() and sets the magma device. inline void initMagma(AccelerationContext const *acceleration){ if (not acceleration->engine->called_magma_init){ magma_init(); acceleration->engine->called_magma_init = std::unique_ptr(new int(1)); } magma_setdevice(acceleration->device); } //! \brief Wrapper around magma_dgeqrf_ooc() inline void geqrf_ooc(int m, int n, double A[], int lda, double tau[]){ int info = 0; double workspace_size; magma_dgeqrf_ooc(m, n, A, lda, tau, &workspace_size, -1, &info); if (info != 0) throw std::runtime_error("magma_dgeqrf_ooc() returned non-zero status: " + std::to_string(info) + " at size-query stage"); double *workspace = nullptr; magma_dmalloc_pinned(&workspace, static_cast(workspace_size)); magma_dgeqrf_ooc(m, n, A, lda, tau, workspace, static_cast(workspace_size), &info); if (info != 0) throw std::runtime_error("magma_dgeqrf_ooc() returned non-zero status: " + std::to_string(info) + " at execute stage"); magma_free_pinned(workspace); } //! \brief Wrapper around magma_dgeqrf_ooc() inline void geqrf_ooc(int m, int n, std::complex A[], int lda, std::complex tau[]){ int info = 0; std::complex workspace_size; magma_zgeqrf_ooc(m, n, reinterpret_cast(A), lda, reinterpret_cast(tau), reinterpret_cast(&workspace_size), -1, &info); if (info != 0) throw std::runtime_error("magma_zgeqrf_ooc() returned non-zero status: " + std::to_string(info) + " at size-query stage"); magmaDoubleComplex *workspace = nullptr; magma_zmalloc_pinned(&workspace, static_cast(std::real(workspace_size))); magma_zgeqrf_ooc(m, n, reinterpret_cast(A), lda, reinterpret_cast(tau), workspace, static_cast(std::real(workspace_size)), &info); if (info != 0) throw std::runtime_error("magma_zgeqrf_ooc() returned non-zero status: " + std::to_string(info) + " at execute stage"); magma_free_pinned(workspace); } //! \brief Wrapper around magma_dormqr() inline void gemqr_ooc(magma_side_t side, magma_trans_t trans, int m, int n, int k, double A[], int lda, double tau[], double C[], int ldc){ int info = 0; std::vector workspace(1); magma_dormqr(side, trans, m, n, k, A, lda, tau, C, ldc, workspace.data(), -1, &info); if (info != 0) throw std::runtime_error("magma_dormqr() returned non-zero status: " + std::to_string(info) + " at size-query stage"); int wsize = static_cast(workspace[0]); workspace.resize(static_cast(wsize)); magma_dormqr(side, trans, m, n, k, A, lda, tau, C, ldc, workspace.data(), wsize, &info); if (info != 0) throw std::runtime_error("magma_dormqr() returned non-zero status: " + std::to_string(info) + " at execute stage"); } //! \brief Wrapper around magma_zunmqr() inline void gemqr_ooc(magma_side_t side, magma_trans_t trans, int m, int n, int k, std::complex A[], int lda, std::complex tau[], std::complex C[], int ldc){ int info = 0; std::vector> workspace(1); magma_zunmqr(side, trans, m, n, k, reinterpret_cast(A), lda, reinterpret_cast(tau), reinterpret_cast(C), ldc, reinterpret_cast(workspace.data()), -1, &info); if (info != 0) throw std::runtime_error("magma_zunmqr() returned non-zero status: " + std::to_string(info) + " at size-query stage"); int wsize = static_cast(std::real(workspace[0])); workspace.resize(static_cast(wsize)); magma_zunmqr(side, trans, m, n, k, reinterpret_cast(A), lda, reinterpret_cast(tau), reinterpret_cast(C), ldc, reinterpret_cast(workspace.data()), wsize, &info); if (info != 0) throw std::runtime_error("magma_zunmqr() returned non-zero status: " + std::to_string(info) + " at execute stage"); } //! \brief Wrapper around magma_dtrsm_m(). inline void trsm_ooc(magma_side_t side, magma_uplo_t uplo, magma_trans_t trans, magma_diag_t diag, int m, int n, double alpha, double const A[], int lda, double B[], int ldb){ magma_dtrsm_m(1, side, uplo, trans, diag, m, n, alpha, A, lda, B, ldb); } //! \brief Wrapper around magma_ztrsm_m(). inline void trsm_ooc(magma_side_t side, magma_uplo_t uplo, magma_trans_t trans, magma_diag_t diag, int m, int n, std::complex alpha, std::complex const A[], int lda, std::complex B[], int ldb){ magma_ztrsm_m(1, side, uplo, trans, diag, m, n, *reinterpret_cast(&alpha), reinterpret_cast(A), lda, reinterpret_cast(B), ldb); } //! \brief Performsthe entire transpose operation. template void solveLSmultiOOC(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]){ initMagma(acceleration); std::vector tau(m); auto AT = Utils::transpose(m, n, A); auto BT = Utils::transpose(nrhs, n, B); geqrf_ooc(n, m, AT.data(), n, tau.data()); gemqr_ooc(MagmaLeft, (std::is_same::value) ? MagmaTrans : MagmaConjTrans, n, nrhs, m, AT.data(), n, tau.data(), BT.data(), n); trsm_ooc(MagmaLeft, MagmaUpper, MagmaNoTrans, MagmaNonUnit, m, nrhs, 1.0, AT.data(), n, BT.data(), n); Utils::transpose(n, nrhs, BT.data(), B); } } } #endif TASMANIAN-8.1/InterfaceTPL/tsgTPLWrappers.hpp000066400000000000000000000065221470551176200206040ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_TPL_WRAPPERS_HPP #define __TASMANIAN_TPL_WRAPPERS_HPP /*! * \internal * \file tsgTPLWrappers.hpp * \brief Wrappers to the enabled TPL functionality. * \author Miroslav Stoyanov * \ingroup TasmanianTPLWrappers * * The header that includes all TPL headers defined by TasmanianConfig.hpp. * \endinternal */ /*! * \internal * \ingroup Tasmanian * \addtogroup TasmanianTPLWrappers Wrappers around TPL functionality * * Tasmanian uses multiple third party libraries (TPL) to gain advanced functionality, * such as optimized liner algebra on the CPU and GPU devices. * The libraries often come with C or Fortran style of API and the included C++ wrappers * help interface with the C++ internals of Tasmanian. * The wrappers are put in a set of private headers and should not be included * as part of the public API. * * \endinternal */ #include "TasmanianConfig.hpp" #ifdef Tasmanian_ENABLE_BLAS #include "tsgBlasWrappers.hpp" #else #include "tsgBlasNull.hpp" #endif #include "tsgGpuWrappers.hpp" #endif TASMANIAN-8.1/LICENSE000066400000000000000000000042631470551176200137170ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2017, Miroslav Stoyanov All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE TASMANIAN-8.1/Makefile000066400000000000000000000256451470551176200143610ustar00rootroot00000000000000#include Config/AltBuildSystems/Makefile.in # disable openmp on non-Linux platforms UNAME = $(shell uname) ifeq ($(UNAME), Linux) OPENMPFLAGS = -fopenmp else OPENMPFLAGS = -Wno-unknown-pragmas endif # Default C++ compiler CC = g++ CXXFLAGS = -O3 -std=c++11 $(OPENMPFLAGS) -fPIC IADD = -I./include -I./SparseGrids/ -I./InterfaceTPL/ -I./DREAM/ -I./DREAM/Optimization/ -I./Addons/ -I./ LADD = -L./ # set the compile command COMPILE = $(CC) $(CXXFLAGS) $(IADD) $(LADD) ECOMPILE = $(CC) $(CXXFLAGS) -I./include # check if Python exists, disable python with TSG_SKIP_PYTHON=1 ifneq ($(shell echo "import numpy; print(numpy.__version__ )" | python3 2>/dev/null),) HAS_PYTHON := "Yes" endif # object files for each target SparseGridsObj = \ ./SparseGrids/tsgIndexSets.o ./SparseGrids/tsgCoreOneDimensional.o ./SparseGrids/tsgIndexManipulator.o ./SparseGrids/tsgGridGlobal.o \ ./SparseGrids/tsgSequenceOptimizer.o ./SparseGrids/tsgLinearSolvers.o ./SparseGrids/tsgGridSequence.o ./SparseGrids/tsgHardCodedTabulatedRules.o \ ./SparseGrids/tsgHierarchyManipulator.o ./SparseGrids/tsgGridLocalPolynomial.o ./SparseGrids/tsgRuleWavelet.o ./SparseGrids/tsgGridWavelet.o \ ./SparseGrids/tsgGridFourier.o ./SparseGrids/tsgDConstructGridGlobal.o ./SparseGrids/tsgAcceleratedDataStructures.o \ ./SparseGrids/TasmanianSparseGridWrapC.o ./SparseGrids/TasmanianSparseGrid.o ./InterfaceTPL/tsgGpuNull.o DREAMObj = \ ./DREAM/tsgDreamState.o ./DREAM/tsgDreamLikelyGaussian.o ./DREAM/tsgDreamSampleWrapC.o \ ./DREAM/Optimization/tsgParticleSwarm.o ./DREAM/Optimization/tsgGradientDescent.o \ ./DREAM/Optimization/TasmanianOptimizationWrapC.o AddonsObj = \ ./Addons/tsgCLoadNeededValues.o ./Addons/tsgCConstructSurrogate.o ./Addons/tsgCLoadUnstructuredPoints.o ./Addons/tsgCExoticQuadrature.o TasgridObj = \ ./Tasgrid/tasgrid_main.o ./SparseGrids/gridtestTestFunctions.o ./SparseGrids/gridtestExternalTests.o ./Tasgrid/tasgridWrapper.o # test objects GidtestObj = \ ./SparseGrids/gridtest_main.o ./SparseGrids/gridtestTestFunctions.o ./SparseGrids/gridtestExternalTests.o \ ./SparseGrids/gridtestUnitTests.o ./SparseGrids/gridtestTestInterfaceC.o DREAMTestObj = \ ./DREAM/dreamtest_main.o ./DREAM/tasdreamExternalTests.o ./DREAM/Optimization/tasdreamOptimizationTests.o AddonTestObj = \ ./Addons/testAddons.o # example objects SGExampleObj = \ ./SparseGrids/Examples/example_sparse_grids.o ./SparseGrids/Examples/example_sparse_grids_01.o \ ./SparseGrids/Examples/example_sparse_grids_02.o ./SparseGrids/Examples/example_sparse_grids_03.o \ ./SparseGrids/Examples/example_sparse_grids_04.o ./SparseGrids/Examples/example_sparse_grids_05.o \ ./SparseGrids/Examples/example_sparse_grids_06.o ./SparseGrids/Examples/example_sparse_grids_07.o \ ./SparseGrids/Examples/example_sparse_grids_08.o ./SparseGrids/Examples/example_sparse_grids_09.o \ ./SparseGrids/Examples/example_sparse_grids_10.o ./SparseGrids/Examples/example_sparse_grids_11.o DREAMExampleObj = \ ./DREAM/Examples/example_dream.o ./DREAM/Examples/example_dream_01.o \ ./DREAM/Examples/example_dream_02.o ./DREAM/Examples/example_dream_03.o \ ./DREAM/Examples/example_dream_04.o ./DREAM/Examples/example_dream_05.o OptExampleObj = \ ./DREAM/Examples/example_optimization.o ./DREAM/Examples/example_optimization_01.o \ ./DREAM/Examples/example_optimization_02.o # all target .PHONY: all all: tasgrid @echo "" @echo "TASMANIAN Simple GNU Make engine:" @echo "Complete build for C/C++, CLI and Python interfaces" @echo "MATLAB interface uses 'make matlab'" # help .PHONY: help help: @echo "TASMANIAN Simple GNU Make tool" @echo " make" @echo " make test" @echo " make examples" @echo " make test_examples" @echo " make matlab" # linear dependence pattern: sparse-grid -> dream -> addons -> python -> tasgrid tasgrid: Tasmanian.py $(TasgridObj) @echo " -- building the tasgrid executable" $(COMPILE) $(TasgridObj) $(SparseGridsObj) -o tasgrid Tasmanian.py: libtasmaniancaddons.so @echo " -- building the Python module" cp ./InterfacePython/TasmanianConfig.in.py TasmanianConfig.py sed -i -e 's|@Tasmanian_VERSION_MAJOR@|'8'|g' ./TasmanianConfig.py sed -i -e 's|@Tasmanian_VERSION_MINOR@|'1'|g' ./TasmanianConfig.py sed -i -e 's|@Tasmanian_license@|'BSD\ 3-Clause\ with\ UT-Battelle\ disclaimer'|g' ./TasmanianConfig.py sed -i -e 's|@Tasmanian_git_hash@|'Tasmanian\ git\ hash\ is\ not\ available\ here'|g' ./TasmanianConfig.py sed -i -e 's|@Tasmanian_libsparsegrid_path@|'`pwd`/libtasmaniansparsegrid.so'|g' ./TasmanianConfig.py sed -i -e 's|@Tasmanian_libdream_path@|'`pwd`/libtasmaniandream.so'|g' ./TasmanianConfig.py sed -i -e 's|@Tasmanian_libcaddons_path@|'`pwd`/libtasmaniancaddons.so'|g' ./TasmanianConfig.py cp ./InterfacePython/Tasmanian* . libtasmaniancaddons.so: libtasmaniandream.so $(AddonsObj) @echo " -- building the Addons module" cp ./Addons/*.hpp ./include/ $(COMPILE) -shared $(AddonsObj) -o libtasmaniancaddons.so ./libtasmaniandream.so ./libtasmaniansparsegrid.so libtasmaniandream.so: libtasmaniansparsegrid.so $(DREAMObj) @echo " -- building the DREAM module" cp ./DREAM/*.hpp ./include/ cp ./DREAM/Optimization/*.hpp ./include/ ar rcs libtasmaniandream.a $(DREAMObj) $(COMPILE) -shared $(DREAMObj) -o libtasmaniandream.so ./libtasmaniansparsegrid.so libtasmaniansparsegrid.so: $(SparseGridsObj) @echo " -- building the Sparse Grid module" cp ./SparseGrids/*.h ./include/ cp ./SparseGrids/*.hpp ./include/ ar rcs libtasmaniansparsegrid.a $(SparseGridsObj) $(COMPILE) -shared $(SparseGridsObj) -o libtasmaniansparsegrid.so %.o: %.cpp ./include $(COMPILE) -c $< -o $@ include: mkdir -p ./include cp ./Tasgrid/tasgridLogs.in.hpp ./include/tasgridLogs.hpp sed -i '/std/,/endl/d' ./include/tasgridLogs.hpp sed -i -e 's|@CMAKE_CURRENT_BINARY_DIR@|'.'|g' ./include/tasgridLogs.hpp sed -i -e 's|@Tasmanian_final_install_path@/share/Tasmanian|'.'|g' ./include/tasgridLogs.hpp sed -i -e 's|}|'std::cout\<\<\"Unavailable\ without\ CMake\"\<\/share/Tasmanian/examples/ ``` * The Examples source code is in: ``` //Examples/ ``` TASMANIAN-8.1/SUPPORT.md000066400000000000000000000001211470551176200143750ustar00rootroot00000000000000# Tasmanian Support Open a GitHub issue or email stoyanovmk @at@ ornl .dot. gov TASMANIAN-8.1/SparseGrids/000077500000000000000000000000001470551176200151335ustar00rootroot00000000000000TASMANIAN-8.1/SparseGrids/Benchmarks/000077500000000000000000000000001470551176200172105ustar00rootroot00000000000000TASMANIAN-8.1/SparseGrids/Benchmarks/benchCommon.hpp000066400000000000000000000210551470551176200221540ustar00rootroot00000000000000#ifndef _TASMANIAN_BENCHMARK_COMMON_HPP #define _TASMANIAN_BENCHMARK_COMMON_HPP #include #include "gridtestCLICommon.hpp" enum BenchFuction{ bench_none, bench_make, bench_loadneeded, bench_evaluate, bench_evaluate_mixed, bench_differentiate, bench_iweights, bench_refine }; BenchFuction getTest(std::string const &s){ std::map str_to_test = { {"evaluate", bench_evaluate}, {"evaluate-mixed", bench_evaluate_mixed}, {"differentiate", bench_differentiate}, {"loadneeded", bench_loadneeded}, {"makegrid", bench_make}, {"iweights", bench_iweights}, {"refine", bench_refine} }; try{ return str_to_test.at(s); }catch(std::out_of_range &){ cout << "ERROR: Unknown test: " << s << endl; return bench_none; } } enum class GridFamily{ none, global, sequence, localp, fourier, wavelet }; GridFamily getGridFamily(std::string const &s){ std::map str_to_rule = { {"global", GridFamily::global}, {"sequence", GridFamily::sequence}, {"localp", GridFamily::localp}, {"fourier", GridFamily::fourier}, {"wavelet", GridFamily::wavelet}, }; GridFamily grid_family = GridFamily::none; try{ grid_family = str_to_rule.at(s); }catch(std::out_of_range &){ cout << "ERROR: Unknown grid type: " << s << endl; } return grid_family; } //! \brief Convert \b s.front() to a grid type indicated by the canonical rules, then \b s.pop_front() the processed string. GridFamily getGridFamily(std::deque &s){ GridFamily grid_family = getGridFamily(s.front()); s.pop_front(); return grid_family; } //! \brief Convert a string to int and advance the iterator. template void readEntry(StringListIterator &iter, int &val){ val = std::stoi(*iter++); } //! \brief Convert a string to double and advance the iterator. template void readEntry(StringListIterator &iter, double &val){ val = std::stod(*iter++); } //! \brief Convert a string to TypeDepth and advance the iterator. template void readEntry(StringListIterator &iter, TypeDepth &val){ val = IO::getDepthTypeString(*iter++); } //! \brief Convert a string to TypeOneDRule and advance the iterator. template void readEntry(StringListIterator &iter, TypeOneDRule &val){ val = IO::getRuleString(*iter++); } //! \brief Convert a string to TypeRefinement and advance the iterator. template void readEntry(StringListIterator &iter, TypeRefinement &val){ val = IO::getTypeRefinementString(*iter++); } //! \brief Convert a string to TypeAcceleration and advance the iterator. template void readEntry(StringListIterator &iter, TypeAcceleration &val){ val = AccelerationMeta::getIOAccelerationString((*iter++).c_str()); } //! \brief Template to terminate recursion, read one entry of type \b ValType and return the iterator. template StringListIterator readEntries(StringListIterator iter, ValType &val){ readEntry(iter, val); return iter; } //! \brief Template to read multiple entries from a string list, returns an iterator past the last processed string. template StringListIterator readEntries(StringListIterator iter, ValType1 &val1, ValType2 &val2, Other & ...others){ readEntry(iter, val1); return readEntries(iter, val2, others...); } //! \brief If the current iterator is pointing to a string dense/sparse return the string and advance, else return "auto" and do nothing. template std::string checkFlavor(StringListIterator &iter, StringListIterator argend){ if (iter == argend) return "auto"; if (*iter == "sparse"){ iter++; return "sparse"; }else if (*iter == "dense"){ iter++; return "dense"; }else{ return "auto"; } } template std::pair, std::vector> extractWeightsLimits(GridFamily grid_family, int num_dimensions, TypeDepth dtype, IteratorToList &arg, IteratorToList const &argend){ std::vector anisotropic_weights; if (grid_family != GridFamily::localp && grid_family != GridFamily::wavelet){ int num_weights = (OneDimensionalMeta::getControurType(dtype) == type_curved) ? 2 * num_dimensions : num_dimensions; for(int i=0; i level_limits; for(int i=0; i getLambdaMakeGrid(GridFamily grid_family, int const &num_dimensions, const int &num_outputs, int const &num_depth, TypeDepth const &dtype, TypeOneDRule const &rule, int const &order, std::pair, std::vector> const &extra){ if (grid_family == GridFamily::global){ return [&]()->TasmanianSparseGrid{ return makeGlobalGrid(num_dimensions, num_outputs, num_depth, dtype, rule, extra.first, 0.0, 0.0, nullptr, extra.second); }; }else if (grid_family == GridFamily::sequence){ return [&]()->TasmanianSparseGrid{ return makeSequenceGrid(num_dimensions, num_outputs, num_depth, dtype, rule, extra.first, extra.second); }; }else if (grid_family == GridFamily::localp){ return [&]()->TasmanianSparseGrid{ return makeLocalPolynomialGrid(num_dimensions, num_outputs, num_depth, order, rule, extra.second); }; }else if (grid_family == GridFamily::fourier){ return [&]()->TasmanianSparseGrid{ return makeFourierGrid(num_dimensions, num_outputs, num_depth, dtype, extra.first, extra.second); }; }else{ // default - wavelet return [&]()->TasmanianSparseGrid{ return makeWaveletGrid(num_dimensions, num_outputs, num_depth, order, extra.second); }; } } template std::vector getRandomVector(int dim1, int dim2, long int seed){ std::vector x(Utils::size_mult(dim1, dim2)); std::minstd_rand park_miller(seed); std::uniform_real_distribution unif(-1.0, 1.0); for(auto &v : x) v = unif(park_miller); return x; } template std::vector> getRandomVectors(int num_vectors, int dim1, int dim2){ std::vector> result((size_t) num_vectors); long int seed = 44; for(auto &r : result) r = getRandomVector(dim1, dim2, seed++); return result; } std::vector getGenericModel(size_t num_dimensions, size_t num_outputs, std::vector const &points){ // model output k = k * exp(sum(x_1 ... x_dims)) size_t num_points = points.size() / num_dimensions; std::vector values(num_points * num_outputs); auto ip = points.begin(); auto iv = values.begin(); while(ip != points.end()){ double exponent = std::exp( std::accumulate(ip, ip + num_dimensions, 0.0) ); std::advance(ip, num_dimensions); for(size_t i = 0; i < num_outputs; i++) *iv++ = double(i) * exponent; } return values; } void loadGenericModel(TasmanianSparseGrid &grid){ if (grid.getNumNeeded() == 0) return; auto values = getGenericModel((size_t) grid.getNumDimensions(), (size_t) grid.getNumOutputs(), grid.getNeededPoints()); grid.loadNeededPoints(values); } struct DryRun{}; struct NoDryRun{}; struct NormalizedTime{}; struct RawTime{}; template int testMethod(int iteratons, std::function test){ if (std::is_same::value) test(iteratons-1); auto time_start = std::chrono::system_clock::now(); for(int i=0; i(time_end - time_start).count(); if (std::is_same::value){ return static_cast( 0.5 + double(elapsed) / double(iteratons) ); }else{ return static_cast(elapsed); } } #endif TASMANIAN-8.1/SparseGrids/Benchmarks/benchDifferentiate.hpp000066400000000000000000000032661470551176200235010ustar00rootroot00000000000000#ifndef _TASMANIAN_BENCHMARK_DIFFERENTIATE_HPP #define _TASMANIAN_BENCHMARK_DIFFERENTIATE_HPP #include "benchCommon.hpp" bool benchmark_differentiate(std::deque &args){ if (args.size() < 9) return false; // report the test parameters to reference later cout << "differentiate"; for(auto &s : args) cout << " " << s; auto grid_family = getGridFamily(args); if (grid_family == GridFamily::none) return false; int num_dimensions, num_outputs, num_depth, order, iteratons, num_jumps; TypeDepth dtype; TypeOneDRule rule; auto riter = readEntries(args.begin(), num_dimensions, num_outputs, num_depth, dtype, rule, order, iteratons, num_jumps); auto extra = extractWeightsLimits(grid_family, num_dimensions, dtype, riter, args.end()); auto make_grid = getLambdaMakeGrid(grid_family, num_dimensions, num_outputs, num_depth, dtype, rule, order, extra); num_jumps = std::max(num_jumps, 1); // make at least one test std::vector> inputs = getRandomVectors(iteratons, num_dimensions, 1); for(int jump = 0; jump < num_jumps; jump++){ auto grid = make_grid(); if (jump == 0) cout << " (points: " << grid.getNumPoints() << ")" << endl; loadGenericModel(grid); if (jump == 0) cout << " note: reporting total time (ms), does not normalize (divide) by iterations\n"; // make one dry-run, using RawTime since each call to differentiate is very fast std::vector result; cout << setw(7) << testMethod(iteratons, [&](int i)->void{ grid.differentiate(inputs[i], result); }) << endl;; num_outputs *= 2; } return true; } #endif TASMANIAN-8.1/SparseGrids/Benchmarks/benchEvaluate.hpp000066400000000000000000000041411470551176200224670ustar00rootroot00000000000000#ifndef _TASMANIAN_BENCHMARK_EVALUATE_HPP #define _TASMANIAN_BENCHMARK_EVALUATE_HPP #include "benchCommon.hpp" bool benchmark_evaluate(std::deque &args, bool use_mixed){ if (args.size() < 12) return false; // report the test parameters to reference later cout << "evaluate"; for(auto &s : args) cout << " " << s; auto grid_family = getGridFamily(args); if (grid_family == GridFamily::none) return false; int num_dimensions, num_outputs, num_depth, order, num_batch, iteratons, num_jumps, device; TypeDepth dtype; TypeOneDRule rule; TypeAcceleration acc; auto riter = readEntries(args.begin(), num_dimensions, num_outputs, num_depth, dtype, rule, order, num_batch, iteratons, num_jumps, acc, device); std::string flavor = checkFlavor(riter, args.end()); auto extra = extractWeightsLimits(grid_family, num_dimensions, dtype, riter, args.end()); auto make_grid = getLambdaMakeGrid(grid_family, num_dimensions, num_outputs, num_depth, dtype, rule, order, extra); num_jumps = std::max(num_jumps, 1); // make at least one test std::vector> inputs = getRandomVectors(iteratons, num_dimensions, num_batch); std::vector> inputsf = getRandomVectors((use_mixed) ? iteratons : 0, num_dimensions, num_batch); for(int jump = 0; jump < num_jumps; jump++){ auto grid = make_grid(); if (jump == 0) cout << " (points: " << grid.getNumPoints() << ")" << endl; loadGenericModel(grid); grid.enableAcceleration(acc, device); if (flavor != "auto") grid.favorSparseAcceleration((flavor == "sparse")); // make one dry-run std::vector result; cout << setw(7) << testMethod(iteratons, [&](int i)->void{ grid.evaluateBatch(inputs[i], result); }); if (use_mixed){ std::vector resultf; cout << setw(7) << testMethod(iteratons, [&](int i)->void{ grid.evaluateBatch(inputsf[i], resultf); }); } cout << endl; num_outputs *= 2; } return true; } #endif TASMANIAN-8.1/SparseGrids/Benchmarks/benchInterpolationWeights.hpp000066400000000000000000000030731470551176200251060ustar00rootroot00000000000000#ifndef _TASMANIAN_BENCHMARK_FFT_HPP #define _TASMANIAN_BENCHMARK_FFT_HPP #include "benchCommon.hpp" bool benchmark_iweights(std::deque &args){ if (args.size() < 8) return false; // report the test parameters to reference later for(auto &s : args) cout << " " << s; cout << endl; auto grid_family = getGridFamily(args); if (grid_family == GridFamily::none) return false; int num_dimensions, num_depth, order, iteratons, num_jumps; TypeDepth dtype; TypeOneDRule rule; auto riter = readEntries(args.begin(), num_dimensions, num_depth, dtype, rule, order, iteratons, num_jumps); auto extra = extractWeightsLimits(grid_family, num_dimensions, dtype, riter, args.end()); int num_outputs = 1; auto make_grid = getLambdaMakeGrid(grid_family, num_dimensions, num_outputs, num_depth, dtype, rule, order, extra); num_jumps = std::max(num_jumps, 1); // make at least one test cout << setw(20) << "points" << setw(20) << "milliseconds" << endl; std::vector> inputs = getRandomVectors(iteratons, num_dimensions, 1); for(int jump = 0; jump < num_jumps; jump++){ auto grid = make_grid(); //grid.printStats(); // uncomment to make sure the right grid is constructed std::vector weights(grid.getNumPoints()); cout << setw(20) << grid.getNumPoints() << setw(20) << testMethod(iteratons, [&](int i)->void{ grid.getInterpolationWeights(inputs[i], weights); }) << endl; num_depth += 1; } return true; } #endif TASMANIAN-8.1/SparseGrids/Benchmarks/benchLoadNeeded.hpp000066400000000000000000000033651470551176200227140ustar00rootroot00000000000000#ifndef _TASMANIAN_BENCHMARK_LOADNEEDED_HPP #define _TASMANIAN_BENCHMARK_LOADNEEDED_HPP #include "benchCommon.hpp" bool benchmark_loadneeded(std::deque &args){ if (args.size() < 11) return false; // report the test parameters to reference later cout << "loadneeded"; for(auto &s : args) cout << " " << s; auto grid_family = getGridFamily(args); if (grid_family == GridFamily::none) return false; int num_dimensions, num_outputs, num_depth, order, iteratons, num_jumps, device; TypeDepth dtype; TypeOneDRule rule; TypeAcceleration acc; auto riter = readEntries(args.begin(), num_dimensions, num_outputs, num_depth, dtype, rule, order, iteratons, num_jumps, acc, device); std::string flavor = checkFlavor(riter, args.end()); auto extra = extractWeightsLimits(grid_family, num_dimensions, dtype, riter, args.end()); auto make_grid = getLambdaMakeGrid(grid_family, num_dimensions, num_outputs, num_depth, dtype, rule, order, extra); for(int jump = 0; jump < num_jumps; jump++){ auto grid = make_grid(); //grid.printStats(); // uncomment to make sure the right grid is constructed if (jump == 0) cout << " (points: " << grid.getNumPoints() << ")" << endl; grid.enableAcceleration(acc, device); if (flavor != "auto") grid.favorSparseAcceleration((flavor == "sparse")); auto values = getGenericModel((size_t) grid.getNumDimensions(), (size_t) grid.getNumOutputs(), grid.getNeededPoints()); cout << setw(7) << testMethod(iteratons, [&](int)->void{ grid.loadNeededPoints(values); }) << endl; num_outputs *= 2; } return true; } #endif TASMANIAN-8.1/SparseGrids/Benchmarks/benchMakeGrid.hpp000066400000000000000000000026451470551176200224130ustar00rootroot00000000000000#ifndef _TASMANIAN_BENCHMARK_MAKEGRID_HPP #define _TASMANIAN_BENCHMARK_MAKEGRID_HPP #include "benchCommon.hpp" bool benchmark_makegrid(std::deque &args){ if (args.size() < 7) return false; // report the test parameters to reference later cout << "makegrid"; for(auto &s : args) cout << " " << s; cout << endl; auto grid_family = getGridFamily(args); if (grid_family == GridFamily::none) return false; int num_dimensions, num_depth, iteratons, num_jumps; TypeDepth dtype; TypeOneDRule rule; auto riter = readEntries(args.begin(), num_dimensions, num_depth, dtype, rule, iteratons, num_jumps); auto extra = extractWeightsLimits(grid_family, num_dimensions, dtype, riter, args.end()); int num_outputs = 1, order = 1; auto make_grid = getLambdaMakeGrid(grid_family, num_dimensions, num_outputs, num_depth, dtype, rule, order, extra); num_jumps = std::max(num_jumps, 1); // make at least one test cout << setw(12) << "num points" << setw(12) << "miliseconds" << endl; for(int jump = 0; jump < num_jumps; jump++){ auto grid = make_grid(); //grid.printStats(); // uncomment to make sure the right grid is constructed cout << setw(12) << grid.getNumPoints() << setw(12) << testMethod(iteratons, [&](int)->void{ auto grid_temp = make_grid(); }) << endl; num_depth += 1; } return true; } #endif TASMANIAN-8.1/SparseGrids/Benchmarks/benchRefine.hpp000066400000000000000000000035331470551176200221350ustar00rootroot00000000000000#ifndef _TASMANIAN_BENCHMARK_REFINE_HPP #define _TASMANIAN_BENCHMARK_REFINE_HPP #include "benchCommon.hpp" bool benchmark_refine(std::deque &args){ if (args.size() < 15) return false; // report the test parameters to reference later cout << "refine"; for(auto &s : args) cout << " " << s; auto grid_family = getGridFamily(args); if (grid_family == GridFamily::none) return false; int num_dimensions, num_outputs, num_depth, order, iteratons; TypeDepth dtype; TypeOneDRule rule; TypeAcceleration acc; int device; TypeDepth ref_aniso_type; int aniso_min_growth; double surp_tolerance; TypeRefinement surp_criteria; int output; auto riter = readEntries(args.begin(), num_dimensions, num_outputs, num_depth, dtype, rule, order, ref_aniso_type, aniso_min_growth, surp_tolerance, surp_criteria, output, iteratons, acc, device); std::string flavor = checkFlavor(riter, args.end()); auto extra = extractWeightsLimits(grid_family, num_dimensions, dtype, riter, args.end()); auto make_grid = getLambdaMakeGrid(grid_family, num_dimensions, num_outputs, num_depth, dtype, rule, order, extra); auto grid = make_grid(); cout << " (points: " << grid.getNumPoints() << ")\n"; loadGenericModel(grid); grid.enableAcceleration(acc, device); if (flavor != "auto") grid.favorSparseAcceleration((flavor == "sparse")); auto test_lambda = [&](int)->void{ if (aniso_min_growth < 1) { grid.setSurplusRefinement(surp_tolerance, surp_criteria, output); } else { grid.setAnisotropicRefinement(ref_aniso_type, aniso_min_growth, output); } }; // make one dry-run cout << setw(7) << testMethod(iteratons, test_lambda) << endl; return true; } #endif TASMANIAN-8.1/SparseGrids/Benchmarks/bench_main.cpp000066400000000000000000000210411470551176200217750ustar00rootroot00000000000000#include "benchMakeGrid.hpp" #include "benchLoadNeeded.hpp" #include "benchEvaluate.hpp" #include "benchDifferentiate.hpp" #include "benchInterpolationWeights.hpp" #include "benchRefine.hpp" void printHelp(BenchFuction test); int main(int argc, const char** argv){ //cout << " Phruuuuphrrr " << endl; // this is the sound that the Tasmanian devil makes std::deque args = stringArgs(argc, argv); if (args.empty() || hasHelp(args.front())){ printHelp(bench_none); return 0; } auto test = getTest(args.front()); args.pop_front(); if ((test == bench_none) || args.empty() || hasHelp(args.front())){ printHelp(test); return (test == bench_none) ? 1 : 0; } bool pass = true; // check if the rest of the inputs are OK switch(test){ case bench_make: pass = benchmark_makegrid(args); break; case bench_loadneeded: pass = benchmark_loadneeded(args); break; case bench_evaluate: case bench_evaluate_mixed: pass = benchmark_evaluate(args, (test == bench_evaluate_mixed)); break; case bench_differentiate: pass = benchmark_differentiate(args); break; case bench_iweights: pass = benchmark_iweights(args); break; case bench_refine: pass = benchmark_refine(args); break; default: throw std::runtime_error("bench_main.cpp: invalid test type in switch statement!"); } if (!pass) // if problem with inputs printHelp(test); return (pass) ? 0 : 1; } void printHelp(BenchFuction test){ if (test == bench_none){ cout << "\nusage: ./benchmark \n\n"; cout << "functions: makegrid, loadneeded, evaluate(-mixed), differentiate, iweights, refine\n"; cout << "\n see: ./benchmark help\n"; }else if (test == bench_make){ cout << "\nusage: ./benchmark makegrid \n\n"; cout << "grid : global, sequence, localp, wavelet, fourier\n"; cout << "dims : number of dimensions\n"; cout << "depth : grid density\n"; cout << "type : level, iptotal, etc.; ignored if not used by the grid\n"; cout << "rule : rleja, clenshaw-curtis, etc.; ignored for wavelet and fourier grids\n"; cout << "iters : number of times to repeat the function call\n"; cout << "jumps : how many times to increment by 1\n"; cout << "aniso : (optional) list of anisotropic weights and level limits\n"; cout << " : anisotropic weights come first (if used by the grid), then level limits\n"; }else if (test == bench_loadneeded){ cout << "\nusage: ./benchmark loadneeded \n\n"; cout << "grid : global, sequence, localp, wavelet, fourier\n"; cout << "dims : number of dimensions\n"; cout << "outs : number of outputs\n"; cout << "depth : grid density\n"; cout << "type : level, iptotal, etc.; ignored if not used by the grid\n"; cout << "rule : rleja, clenshaw-curtis, etc.; ignored for wavelet and fourier grids\n"; cout << "order : -1, 0, 1, 2; ignored if not used by the grid\n"; cout << "iters : number of times to repeat the function call\n"; cout << "jumps : how many times to double \n"; cout << "acc : acceleration type, e.g., gpu-cuda, cpu-blas, none, etc.\n"; cout << "gpu : cuda device ID; ignored for cpu acceleration\n"; cout << "extra : (optional) sparse/dense flavor and/or list of anisotropic weights and level limits\n"; cout << " : anisotropic weights come first (if used by the grid), then level limits\n"; }else if (test == bench_evaluate || test == bench_evaluate_mixed){ cout << "\nusage: ./benchmark evaluate \n\n"; cout << "grid : global, sequence, localp, wavelet, fourier\n"; cout << "dims : number of dimensions\n"; cout << "outs : number of outputs\n"; cout << "depth : grid density\n"; cout << "type : level, iptotal, etc.; ignored if not used by the grid\n"; cout << "rule : rleja, clenshaw-curtis, etc.; ignored for wavelet and fourier grids\n"; cout << "order : -1, 0, 1, 2; ignored if not used by the grid\n"; cout << "batch : number of points to use for the evaluate command\n"; cout << "iters : number of times to repeat the function call\n"; cout << "jumps : how many times to double \n"; cout << "acc : acceleration type, e.g., gpu-cuda, cpu-blas, none, etc.\n"; cout << "gpu : cuda device ID; ignored for cpu acceleration\n"; cout << "extra : (optional) sparse/dense flavor and/or list of anisotropic weights and level limits\n"; cout << " : anisotropic weights come first (if used by the grid), then level limits\n"; }else if (test == bench_differentiate){ cout << "\nusage: ./benchmark differentiate \n\n"; cout << "grid : global, sequence, localp, wavelet, fourier\n"; cout << "dims : number of dimensions\n"; cout << "outs : number of outputs\n"; cout << "depth : grid density\n"; cout << "type : level, iptotal, etc.; ignored if not used by the grid\n"; cout << "rule : rleja, clenshaw-curtis, etc.; ignored for wavelet and fourier grids\n"; cout << "order : -1, 0, 1, 2; ignored if not used by the grid\n"; cout << "iters : number of times to repeat the function call\n"; cout << "jumps : how many times to double \n"; cout << "extra : (optional) sparse/dense flavor and/or list of anisotropic weights and level limits\n"; cout << " : anisotropic weights come first (if used by the grid), then level limits\n"; }else if (test == bench_iweights){ cout << "\nusage: ./benchmark iweights \n\n"; cout << "grid : global, sequence, localp, wavelet, fourier\n"; cout << "dims : number of dimensions\n"; cout << "depth : grid density\n"; cout << "type : level, iptotal, etc.; ignored if not used by the grid\n"; cout << "rule : rleja, clenshaw-curtis, etc.; ignored for wavelet and Fourier grids\n"; cout << "order : -1, 0, 1, 2; ignored if not used by the grid\n"; cout << "iters : number of times to repeat the function call\n"; cout << "jumps : how many times to increase by 1\n"; cout << "aniso : (optional) list of anisotropic weights and level limits\n"; cout << " : anisotropic weights come first (if used by the grid), then level limits\n"; }else if (test == bench_refine){ cout << "\nusage: ./benchmark refine \n\n"; cout << "grid : global, sequence, localp, wavelet, fourier\n"; cout << "dims : number of dimensions\n"; cout << "outs : number of outputs\n"; cout << "depth : grid density\n"; cout << "type : level, iptotal, etc.; ignored if not used by the grid\n"; cout << "rule : rleja, clenshaw-curtis, etc.; ignored for wavelet and fourier grids\n"; cout << "order : -1, 0, 1, 2; ignored if not used by the grid\n\n"; cout << "ref-type-depth : (anisotropic refinement) refinement type, e.g., iptotal, ipcurved\n"; cout << "min-growth : (anisotropic refinement) minumum number of refinement points, use 0 to switch to surplus refinement\n"; cout << "surp-tolerance : (surplus refinement) tolerance\n"; cout << "surp-criteria : (surplus refinement) selection criteria, e.g., stable, fds\n"; cout << "output : (all refinement) output to use in the refinement\n\n"; cout << "iters : number of times to repeat the function call\n"; cout << "acc : acceleration type, e.g., gpu-cuda, cpu-blas, none, etc.\n"; cout << "gpu : cuda device ID; ignored for cpu acceleration\n"; cout << "extra : (optional) list of anisotropic weights and level limits\n"; cout << " : anisotropic weights come first (if used by the grid), then level limits\n"; } cout << endl; } TASMANIAN-8.1/SparseGrids/CMakeLists.txt000066400000000000000000000232201470551176200176720ustar00rootroot00000000000000######################################################################## # Sparse Grid libraries and gridtest command line tool ######################################################################## ######################################################################## # Define source files # in order to avoid GLOB, list all source files for add_library() ######################################################################## # source files specific to cuda/hip, used for both static and shared libs set(Tasmanian_source_libsparsegrid_cuda ${CMAKE_CURRENT_SOURCE_DIR}/../InterfaceTPL/tsgCudaWrappers.cpp tsgCudaKernels.cu) set(Tasmanian_source_libsparsegrid_hip ${CMAKE_CURRENT_SOURCE_DIR}/../InterfaceTPL/tsgHipWrappers.cpp tsgHipKernels.hip.cpp) set(Tasmanian_sparse_grid_null_backend ON) if (Tasmanian_ENABLE_CUDA OR Tasmanian_ENABLE_HIP OR Tasmanian_ENABLE_DPCPP) set(Tasmanian_sparse_grid_null_backend OFF) endif() add_library(Tasmanian_libsparsegrid TasmanianSparseGrid.hpp TasmanianSparseGrid.cpp TasmanianSparseGridWrapC.cpp tsgAcceleratedHandles.hpp tsgAcceleratedDataStructures.hpp tsgAcceleratedDataStructures.cpp tsgCacheLagrange.hpp tsgCoreOneDimensional.hpp tsgCoreOneDimensional.cpp tsgDConstructGridGlobal.hpp tsgDConstructGridGlobal.cpp tsgCudaLoadStructures.hpp tsgEnumerates.hpp tsgGridCore.hpp tsgGridGlobal.hpp tsgGridGlobal.cpp tsgGridWavelet.hpp tsgGridWavelet.cpp tsgHardCodedTabulatedRules.hpp tsgHardCodedTabulatedRules.cpp tsgGridLocalPolynomial.hpp tsgGridLocalPolynomial.cpp tsgGridSequence.hpp tsgGridSequence.cpp tsgGridFourier.hpp tsgGridFourier.cpp tsgIndexManipulator.hpp tsgIndexManipulator.cpp tsgHierarchyManipulator.hpp tsgHierarchyManipulator.cpp tsgIOHelpers.hpp tsgIndexSets.hpp tsgIndexSets.cpp tsgLinearSolvers.hpp tsgLinearSolvers.cpp tsgOneDimensionalWrapper.hpp tsgRuleLocalPolynomial.hpp tsgRuleWavelet.hpp tsgRuleWavelet.cpp tsgSequenceOptimizer.hpp tsgSequenceOptimizer.cpp tsgMathUtils.hpp tsgUtils.hpp $<$:${CMAKE_CURRENT_SOURCE_DIR}/../InterfaceTPL/tsgGpuNull.cpp> $<$:${Tasmanian_source_libsparsegrid_cuda}> $<$:${Tasmanian_source_libsparsegrid_hip}> $<$:${CMAKE_CURRENT_SOURCE_DIR}/../InterfaceTPL/tsgDpcppWrappers.cpp> $<$:${CMAKE_CURRENT_SOURCE_DIR}/tsgDpcppKernels.cpp> ) ######################################################################## # add the gridtest and examples executables ######################################################################## add_executable(Tasmanian_gridtest gridtest_main.cpp TasmanianSparseGrid.hpp gridtestCLICommon.hpp gridtestExternalTests.hpp gridtestExternalTests.cpp gridtestTestHelpers.hpp gridtestTestFunctions.hpp gridtestTestFunctions.cpp gridtestUnitTests.hpp gridtestUnitTests.cpp gridtestTestInterfaceC.cpp) add_executable(Tasmanian_benchmarksgrid Benchmarks/benchCommon.hpp gridtestCLICommon.hpp Benchmarks/benchMakeGrid.hpp Benchmarks/benchLoadNeeded.hpp Benchmarks/benchDifferentiate.hpp Benchmarks/benchEvaluate.hpp Benchmarks/benchRefine.hpp Benchmarks/bench_main.cpp) if (Tasmanian_ENABLE_CUDA) # CMake does not automatically add the CUDA include path, any source file that adds directly or transitively # must be labeled as "CUDA" source files and compiled with the nvcc compiler. # Beware that the nvcc compiler seems to struggle with some STL algorithms, transitive inclusion of must be minimized. set_source_files_properties(${Tasmanian_source_libsparsegrid_cuda} PROPERTIES LANGUAGE CUDA) set_property(TARGET Tasmanian_libsparsegrid PROPERTY CUDA_STANDARD 11) elseif(Tasmanian_ENABLE_HIP) set_source_files_properties(${Tasmanian_source_libsparsegrid_hip} PROPERTIES LANGUAGE HIP) elseif(Tasmanian_ENABLE_DPCPP) target_compile_options(Tasmanian_libsparsegrid PRIVATE -fsycl) target_compile_options(Tasmanian_gridtest PRIVATE -fsycl) target_link_options(Tasmanian_libsparsegrid PRIVATE -fsycl) target_link_options(Tasmanian_gridtest PRIVATE -fsycl) endif() target_link_libraries(Tasmanian_libsparsegrid Tasmanian_dependencies) target_include_directories(Tasmanian_libsparsegrid PUBLIC $) set_target_properties(Tasmanian_libsparsegrid PROPERTIES OUTPUT_NAME "tasmaniansparsegrid" SOVERSION ${Tasmanian_VERSION_MAJOR} VERSION ${PROJECT_VERSION}) Tasmanian_rpath_target(TARGET Tasmanian_libsparsegrid) if (Tasmanian_ENABLE_OPENMP) # the nvcc compiler does nor recognize OpenMP, add the flag only to non-CUDA source files target_compile_options(Tasmanian_libsparsegrid PRIVATE $<$:${OpenMP_CXX_FLAGS}>) endif() install(TARGETS Tasmanian_libsparsegrid EXPORT "${Tasmanian_export_name}" RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib") foreach(_tsgtarget gridtest benchmarksgrid) target_link_libraries(Tasmanian_${_tsgtarget} Tasmanian_libsparsegrid) set_target_properties(Tasmanian_${_tsgtarget} PROPERTIES OUTPUT_NAME "${_tsgtarget}" CXX_EXTENSIONS OFF) Tasmanian_rpath_target(TARGET Tasmanian_${_tsgtarget} USE_CURRENT) if (Tasmanian_ENABLE_OPENMP) # the OpenMP libraries are carried transitively from sparse grids library target_compile_options(Tasmanian_${_tsgtarget} PRIVATE ${OpenMP_CXX_FLAGS}) endif() if (Tasmanian_ENABLE_HIP) target_link_libraries(Tasmanian_${_tsgtarget} hip::host) endif() endforeach() unset(_tsgtarget) # data file, needed for testing and reference about custom rule definitions configure_file("${CMAKE_CURRENT_SOURCE_DIR}/GaussPattersonRule.table" "${CMAKE_CURRENT_BINARY_DIR}/GaussPattersonRule.table" COPYONLY) ######################################################################## # Windows specific support (DLL export/import directives and names) ######################################################################## if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") foreach(_tsg_target libsparsegrid gridtest) # suppresses warnings regarding pointers to the middle of an array target_compile_definitions(Tasmanian_${_tsg_target} PRIVATE -D_SCL_SECURE_NO_WARNINGS) # needed to prevent crash on using STL vector iterators target_compile_definitions(Tasmanian_${_tsg_target} PUBLIC -D_HAS_ITERATOR_DEBUGGING=0) endforeach() unset(_tsg_target) if (BUILD_SHARED_LIBS) set_target_properties(Tasmanian_libsparsegrid PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) endif() endif() ######################################################################## # Testing ######################################################################## add_test(SparseGridsAcceleration gridtest acceleration -gpuid ${Tasmanian_TESTS_GPU_ID}) add_test(SparseGridsDomain gridtest domain) add_test(SparseGridsRefinement gridtest refinement) add_test(SparseGridsGlobal gridtest global) add_test(SparseGridsLocal gridtest local) add_test(SparseGridsWavelet gridtest wavelet) add_test(SparseGridsFourier gridtest fourier) add_test(SparseGridsExceptions gridtest errors) add_test(SparseGridsAPI gridtest api) add_test(SparseGridsC gridtest c) Tasmanian_set_test_properties(TESTS SparseGridsAcceleration SparseGridsDomain SparseGridsRefinement SparseGridsGlobal SparseGridsLocal SparseGridsWavelet SparseGridsFourier SparseGridsExceptions SparseGridsAPI SparseGridsC) if (Tasmanian_ENABLE_BLAS) add_test(SparseGridsLAPACK gridtest lapack) Tasmanian_set_test_properties(TESTS SparseGridsLAPACK) endif() ######################################################################## # Install headers and config files ######################################################################## install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" DESTINATION include FILES_MATCHING PATTERN "*.hpp" PATTERN "*.windows.*" EXCLUDE PATTERN "Examples" EXCLUDE PATTERN "Benchmarks" EXCLUDE PATTERN "tsgHiddenExternals.hpp" EXCLUDE) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/TasmanianSparseGrid.h" DESTINATION include PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Examples/" DESTINATION "share/Tasmanian/examples/" FILES_MATCHING PATTERN "*.cpp" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/GaussPattersonRule.table" DESTINATION "share/Tasmanian/" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) TASMANIAN-8.1/SparseGrids/Examples/000077500000000000000000000000001470551176200167115ustar00rootroot00000000000000TASMANIAN-8.1/SparseGrids/Examples/example_sparse_grids.cpp000066400000000000000000000075651470551176200236320ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ /*! * \internal * \file example_sparse_grids.cpp * \brief Examples for the Tasmanian Sparse Grid module. * \author Miroslav Stoyanov * \ingroup TasmanianSGExamples * * The main file that runs all sparse grid examples. */ /*! * \defgroup TasmanianSGExamples Examples for the Tasmanian Sparse Grid module * * Several examples are included that demonstrate the proper usage of * the TasmanianSparseGrid class. * The examples include quadrature and interpolation tasks, * as well as constructing surrogates from random data. */ #ifndef __TASMANIAN_DOXYGEN_SKIP void sparse_grids_example_01(); void sparse_grids_example_02(); void sparse_grids_example_03(); void sparse_grids_example_04(); void sparse_grids_example_05(); void sparse_grids_example_06(); void sparse_grids_example_07(); void sparse_grids_example_08(); void sparse_grids_example_09(); void sparse_grids_example_10(); void sparse_grids_example_11(); int main(int argc, const char**){ // some of the examples take long time, for post-install testing purposes // optionally limit examples to the first 3 bool limit_examples = (argc > 1); sparse_grids_example_01(); sparse_grids_example_02(); sparse_grids_example_03(); sparse_grids_example_04(); if (limit_examples) return 0; // skip the more expensive examples sparse_grids_example_05(); sparse_grids_example_06(); sparse_grids_example_07(); sparse_grids_example_08(); sparse_grids_example_09(); sparse_grids_example_10(); sparse_grids_example_11(); return 0; } #endif // __TASMANIAN_DOXYGEN_SKIP TASMANIAN-8.1/SparseGrids/Examples/example_sparse_grids_01.cpp000066400000000000000000000052361470551176200241230ustar00rootroot00000000000000 #include "Tasmanian.hpp" using namespace std; /*! * \internal * \file example_sparse_grids_01.cpp * \brief Examples for the Tasmanian Sparse Grid module. * \author Miroslav Stoyanov * \ingroup TasmanianSGExamples * * Tasmanian Sparse Grids Example 1. * \endinternal */ /*! * \ingroup TasmanianSGExamples * \addtogroup TasmanianSGExamples1 Tasmanian Sparse Grids module, example 1 * * \par Example 1 * Compute \f$ \int_{-1}^{+1} \int_{-1}^{+1} \exp(-x^2) \cos(y) dy dx \f$ * using a sparse grid with Clenshaw-Curtis nodes and weights. */ /*! * \ingroup TasmanianSGExamples1 * \brief Sparse Grids Example 1: integrate a simple function over a canonical domain. * * \snippet SparseGrids/Examples/example_sparse_grids_01.cpp SG_Example_01 example */ void sparse_grids_example_01(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_01 example] #endif cout << "\n---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(17); cout << "Example 1: integrate f(x,y) = exp(-x^2) * cos(y),\n" << " using clenshaw-curtis nodes and grid of type level\n"; int dimension = 2; int level = 6; TasGrid::TasmanianSparseGrid grid; grid.makeGlobalGrid(dimension, 0, level, TasGrid::type_level, TasGrid::rule_clenshawcurtis); std::vector points = grid.getPoints(); std::vector weights = grid.getQuadratureWeights(); int num_points = grid.getNumPoints(); // also equal to weights.size() double I = 0.0; for(int i=0; i TasGrid::TasmanianSparseGrid{ auto grid = TasGrid::makeGlobalGrid(dimensions, 0, precision, TasGrid::type_qptotal, rule); grid.setDomainTransform({-5.0, -5.0, -2.0, -2.0}, {5.0, 5.0, 3.0, 3.0}); return grid; }; // computes the integral using the quadrature provided by the grid // then prints the number of points and the error auto print_error = [&](TasGrid::TasmanianSparseGrid const &grid)-> void{ auto points = grid.getPoints(); auto weights = grid.getQuadratureWeights(); double integral = 0.0; for(size_t i=0; i pnts = { 0.3, 0.7 }; // points of interest where the model is not known double reference_solution = std::exp(-0.3 * 0.3) * std::cos(0.7); std::vector polynomial_order = {6, 12}; // use two grids with different polynomial order for(auto prec : polynomial_order){ // the first 3 inputs to make grid are always: inputs, outputs, depth // TasGrid::type_iptotal means interpret the precision as "total degree polynomial space" auto grid = TasGrid::makeGlobalGrid(num_inputs, num_outputs, prec, TasGrid::type_iptotal, TasGrid::rule_clenshawcurtis); // having constructed the initial grid // to complete the interpolant, Tasmanian needs the model values at the needed points auto points = grid.getNeededPoints(); // allocate a vector for the associated model values std::vector model_values(grid.getNumNeeded() * num_outputs); for(int i=0; i result(num_samples * num_outputs); // evaluate() deals with a single point // if num_samples is large, evaluateBatch() is much more efficient grid.evaluate(pnts, result); cout << "\n using polynomials of total degree up to: " << prec << "\n" << " the grid has: " << grid.getNumPoints() << " poitns\n" << " interpolant at (0.3,0.7): " << result[0] << "\n" << " error: " << std::abs(result[0] - reference_solution) << "\n"; } #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_04 example] #endif } TASMANIAN-8.1/SparseGrids/Examples/example_sparse_grids_05.cpp000066400000000000000000000140031470551176200241170ustar00rootroot00000000000000 #include "Tasmanian.hpp" #include 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 test_points(num_test_points * num_inputs); std::minstd_rand park_miller(42); std::uniform_real_distribution domain(-1.0, 1.0); for(auto &t : test_points) t = domain(park_miller); std::vector reference_values(num_test_points * num_outputs); for(int i=0; i double{ std::vector result; grid.evaluateBatch(test_points, result); double diff = 0.0; for(int i=0; i using namespace std; /*! * \internal * \file example_sparse_grids_06.cpp * \brief Examples for the Tasmanian Sparse Grid module. * \author Miroslav Stoyanov * \ingroup TasmanianSGExamples * * Tasmanian Sparse Grids Example 6. * \endinternal */ /*! * \ingroup TasmanianSGExamples * \addtogroup TasmanianSGExamples6 Tasmanian Sparse Grids module, example 6 * * \par Example 6 * Build a surrogate model using automatic construction. */ /*! * \ingroup TasmanianSGExamples6 * \brief Sparse Grids Example 6: adaptive surrogate modeling * * Example 5 demonstrates how to construct a surrogate by processing * the samples in batches. The batch construction can facilitate * parallel sampling, but the exact number of samples is hard to control * since the points from the entire batch are needed at once. * Furthermore, if a fixed number of computing nodes is available * (e.g., processor cores or MPI ranks) it may be hard to keep all * nodes loaded if the batch size does not divide evenly. * * The construction procedure offers a more flexible refinement alternative. * The batch size can be controlled at a much finer scale to accommodate * a fixed budget and occupancy across all parallel resources can be guaranteed * (unless the level limits or tolerance are about to be reached, * or the initial grid is too coarse). * See the documentation for TasGrid::mpiConstructSurrogate() for * the MPI variant of this method that differs only in some MPI related * parameters. * * \snippet SparseGrids/Examples/example_sparse_grids_06.cpp SG_Example_06 example */ void sparse_grids_example_06(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_06 example] #endif cout << "\n---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(4); cout << "Example 6: interpolate f(x,y) = exp(-x^2) * exp(y) * cos(z), using the rleja rule\n" << " employs adaptive construction\n"; // define the model as a C++ lambda expression, the advantage of lambdas // is that they can wrap around very complex models // the construction signature uses std::vector int const num_inputs = 3; int const num_outputs = 1; auto model = [&](std::vector const &x, std::vector &y, size_t)-> void{ // if no initial guess is used, then y will be guaranteed to have // the correct size, i.e., num_outputs // otherwise, y must be correctly resized y.resize(num_outputs); y[0] = std::exp(-x[0] * x[0]) * std::exp(x[1]) * std::cos(x[2]); }; // the accuracy of the surrogate models is measure from 1000 random reference points int const num_test_points = 1000; std::vector test_points(num_test_points * num_inputs); std::minstd_rand park_miller(42); std::uniform_real_distribution domain(-1.0, 1.0); for(auto &t : test_points) t = domain(park_miller); std::vector reference_values(num_test_points * num_outputs); for(int i=0; i y(1); model(std::vector(test_points.begin() + i * num_inputs, test_points.begin() + (i+1) * num_inputs), y, 0); std::copy(y.begin(), y.end(), reference_values.begin() + i * num_outputs); } // computes the maximum error between the reference values and the grid interpolant auto test_grid = [&](TasGrid::TasmanianSparseGrid const &grid)-> double{ std::vector result; grid.evaluateBatch(test_points, result); double diff = 0.0; for(int i=0; i(model, budget, 12, 1, grid, TasGrid::type_iptotal, 0); cout << setw(10) << grid.getNumPoints() << setw(20) << test_grid(grid) << "\n"; } // Note: when using a sequence rule, the actual number of points always matches the budget // but this cannot be guaranteed for rules that grow by more than one node per level // because a tensor can be added only when all points are present and each tensor requires // more than one point // for fast growing rules, sometime it is simply not possible to build a grid // with exactly the given number of points #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_06 example] #endif } TASMANIAN-8.1/SparseGrids/Examples/example_sparse_grids_07.cpp000066400000000000000000000141131470551176200241230ustar00rootroot00000000000000 #include "Tasmanian.hpp" #include #include using namespace std; /*! * \internal * \file example_sparse_grids_07.cpp * \brief Examples for the Tasmanian Sparse Grid module. * \author Miroslav Stoyanov * \ingroup TasmanianSGExamples * * Tasmanian Sparse Grids Example 7. * \endinternal */ /*! * \ingroup TasmanianSGExamples * \addtogroup TasmanianSGExamples7 Tasmanian Sparse Grids module, example 7 * * \par Example 7 * Benchmark Global vs. Sequence grids. */ /*! * \ingroup TasmanianSGExamples7 * \brief Sparse Grids Example 7: Global vs. Sequence grids * * Sequence rules are those that form the next level by adding one point to the previous one, * in Tasmanian those rules are: TasGrid::rule_leja, TasGrid::rule_rleja, TasGrid::rule_rlejashifted, * TasGrid::rule_maxlebesgue, TasGrid::rule_minlebesgue, TasGrid::rule_mindelta. * Two implementations are provided that deal with such rules, Global grids that use * the standard Lagrange polynomial interpolation and Sequence grids that use Newton polynomials. * Mathematically the two implementations yield the same result (to within rounding error), * but the two processes can have very different computational overhead. * Sequence grids offer much faster TasmanianSparseGrid::evaluate() and TasmanianSparseGrid::evaluateBatch() * algorithms, at the cost of nearly double the storage and more than double the cost * of TasmanianSparseGrid::loadNeededValues(). * * This example serves as a simple demonstration of the difference. * * \snippet SparseGrids/Examples/example_sparse_grids_07.cpp SG_Example_07 example */ void sparse_grids_example_07(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_07 example] #endif cout << "\n---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(4); cout << "Example 7: interpolate f(x_1, x_2, x_3, x_4) = exp(-x_1^2 - x_3^2) * exp(x_2) * cos(x_4)\n" << " using rleja rule and comparing Global and Sequence grids\n"; auto time_start = std::chrono::system_clock::now(); auto global = TasGrid::makeGlobalGrid(4, 1, 15, TasGrid::type_iptotal, TasGrid::rule_leja); auto time_end = std::chrono::system_clock::now(); long long make_global = std::chrono::duration_cast(time_end - time_start).count(); time_start = std::chrono::system_clock::now(); auto sequence = TasGrid::makeSequenceGrid(4, 1, 15, TasGrid::type_iptotal, TasGrid::rule_leja); time_end = std::chrono::system_clock::now(); long long make_sequence = std::chrono::duration_cast(time_end - time_start).count(); // define batch model auto model = [](std::vector const &points)-> std::vector{ size_t num_points = points.size() / 4; std::vector result(num_points); for(size_t i=0; i(time_end - time_start).count(); time_start = std::chrono::system_clock::now(); sequence.loadNeededValues(model(sequence.getNeededPoints())); time_end = std::chrono::system_clock::now(); long long load_sequence = std::chrono::duration_cast(time_end - time_start).count(); // the benchmark surrogate models is measure from 1000 random reference points int const num_test_points = 1000; std::vector test_points(4 * num_test_points); std::minstd_rand park_miller(42); std::uniform_real_distribution domain(-1.0, 1.0); for(auto &t : test_points) t = domain(park_miller); // reference points std::vector reference_result = model(test_points); // get the surrogate values at the test points time_start = std::chrono::system_clock::now(); std::vector global_result; global.evaluateBatch(test_points, global_result); time_end = std::chrono::system_clock::now(); long long eval_global = std::chrono::duration_cast(time_end - time_start).count(); time_start = std::chrono::system_clock::now(); std::vector sequence_result; sequence.evaluateBatch(test_points, sequence_result); time_end = std::chrono::system_clock::now(); long long eval_sequence = std::chrono::duration_cast(time_end - time_start).count(); double global_error = 0.0; for(int i=0; i using namespace std; /*! * \internal * \file example_sparse_grids_08.cpp * \brief Examples for the Tasmanian Sparse Grid module. * \author Miroslav Stoyanov * \ingroup TasmanianSGExamples * * Tasmanian Sparse Grids Example 8. * \endinternal */ /*! * \ingroup TasmanianSGExamples * \addtogroup TasmanianSGExamples8 Tasmanian Sparse Grids module, example 8 * * \par Example 8 * Different local polynomial rules. */ /*! * \ingroup TasmanianSGExamples8 * \brief Sparse Grids Example 8: local polynomial rules * * Local polynomial grids use a hierarchy of basis functions with decreasing support, * Tasmanian offers several different types of basis each tuned to different types * of models. This example demonstrates the efficiency (i.e., error per number of points) * of different local polynomial grids when applied to different models. * * \snippet SparseGrids/Examples/example_sparse_grids_08.cpp SG_Example_08 example */ void sparse_grids_example_08(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_08 example] #endif cout << "\n---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(4); cout << "Example 8: interpolate different functions demonstrating the different\n" << " local polynomial rules\n\n"; int const num_inputs = 2; // using two inputs for all tests // using random points to test the error int const num_test_points = 1000; std::vector test_points(num_test_points * num_inputs); std::minstd_rand park_miller(42); std::uniform_real_distribution domain(-1.0, 1.0); for(auto &t : test_points) t = domain(park_miller); // computes the error between the gird surrogate model and the actual model // using the test points, finds the largest absolute error auto get_error = [&](TasGrid::TasmanianSparseGrid const &grid, std::function model)-> double{ std::vector grid_result; grid.evaluateBatch(test_points, grid_result); double err = 0.0; for(int i=0; i void{ y[0] = std::exp(-x[0] * x[0]) * std::cos(x[1]); }; int const order = 2; // at order 1 localp and semilocalp are identical auto grid_localp = TasGrid::makeLocalPolynomialGrid(num_inputs, 1, 7, order, TasGrid::rule_localp); auto grid_semilocalp = TasGrid::makeLocalPolynomialGrid(num_inputs, 1, 7, order, TasGrid::rule_semilocalp); TasGrid::loadNeededValues(smooth_model, grid_localp, 4); TasGrid::loadNeededValues(smooth_model, grid_semilocalp, 4); cout << "Using smooth model: f(x, y) = exp(-x*x) * cos(y)\n" << " rule_localp, points = " << grid_localp.getNumPoints() << " error = " << get_error(grid_localp, smooth_model) << "\n" << " rule_semilocalp, points = " << grid_semilocalp.getNumPoints() << " error = " << get_error(grid_semilocalp, smooth_model) << "\n" << " If the model is smooth, rule_semilocalp has an advantage.\n\n"; // test 1: using model with zero-boundary conditions constexpr double pi = 3.14159265358979323846; auto zero_model = [=](double const x[], double y[], size_t)-> void{ y[0] = std::cos(0.5 * pi * x[0]) * std::cos(0.5 * pi * x[1]); }; auto grid_localp0 = TasGrid::makeLocalPolynomialGrid(num_inputs, 1, 6, order, TasGrid::rule_localp0); // the true value indicates overwrite of the currently loaded model TasGrid::loadNeededValues(zero_model, grid_localp, 4); TasGrid::loadNeededValues(zero_model, grid_localp0, 4); cout << "Using homogeneous model: f(x, y) = cos(pi * x / 2) * cos(pi * y / 2)\n" << " rule_localp, points = " << grid_localp.getNumPoints() << " error = " << get_error(grid_localp, zero_model) << "\n" << " rule_localp0, points = " << grid_localp0.getNumPoints() << " error = " << get_error(grid_localp0, zero_model) << "\n" << " The rule_localp0 uses basis tuned for models with zero boundary.\n"; #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_08 example] #endif } TASMANIAN-8.1/SparseGrids/Examples/example_sparse_grids_09.cpp000066400000000000000000000133721470551176200241330ustar00rootroot00000000000000 #include "Tasmanian.hpp" #include using namespace std; /*! * \internal * \file example_sparse_grids_09.cpp * \brief Examples for the Tasmanian Sparse Grid module. * \author Miroslav Stoyanov * \ingroup TasmanianSGExamples * * Tasmanian Sparse Grids Example 9. * \endinternal */ /*! * \ingroup TasmanianSGExamples * \addtogroup TasmanianSGExamples9 Tasmanian Sparse Grids module, example 9 * * \par Example 9 * Different local polynomial refinement. */ /*! * \ingroup TasmanianSGExamples9 * \brief Sparse Grids Example 9: local polynomial refinement * * Example 8 showed the difference between the local polynomial rules and how * the basis can be tuned to a specific model. This example shows refinement * in the local polynomial context using hierarchical coefficients (surpluses). * A sharp model is selected so that TasGrid::rule_localp is the natural choice, * and two different refinement strategies are tested. * * \b Note: the refinement process can be used in the context of construction, * e.g., similar to Example 6 and TasGrid::constructSurrogate(). * * \snippet SparseGrids/Examples/example_sparse_grids_09.cpp SG_Example_09 example */ void sparse_grids_example_09(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_09 example] #endif cout << "\n---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(4); cout << "Example 9: comparison between local polynomial refinement strategies\n\n"; int const num_inputs = 2; // using random points to test the error int const num_test_points = 1000; std::vector test_points(num_test_points * num_inputs); std::minstd_rand park_miller(42); std::uniform_real_distribution domain(-1.0, 1.0); for(auto &t : test_points) t = domain(park_miller); // computes the error between the gird surrogate model and the actual model // using the test points, finds the largest absolute error auto get_error = [&](TasGrid::TasmanianSparseGrid const &grid, std::function model)-> double{ std::vector grid_result; grid.evaluateBatch(test_points, grid_result); double err = 0.0; for(int i=0; i void{ y[0] = exp(-x[0]) / (1.0 + 100.0 * exp(-10.0 * x[1])); }; // using maximal order int const order = -1; auto grid_classic = TasGrid::makeLocalPolynomialGrid(num_inputs, 1, 2, order, TasGrid::rule_localp); auto grid_fds = TasGrid::copyGrid(grid_classic); // setup the top rows of the output table cout << "Using batch refinement:\n" << setw(22) << "classic" << setw(22) << "fds\n" << setw(8) << "points" << setw(14) << "error" << setw(8) << "points" << setw(14) << "error\n"; double const tolerance = 1.E-5; while((grid_classic.getNumNeeded() > 0) || (grid_fds.getNumNeeded() > 0)){ TasGrid::loadNeededValues(sharp_model, grid_classic, 4); TasGrid::loadNeededValues(sharp_model, grid_fds, 4); // output the grids and results at the current stage cout << setw(8) << grid_classic.getNumLoaded() << setw(14) << get_error(grid_classic, sharp_model) << setw(8) << grid_fds.getNumLoaded() << setw(14) << get_error(grid_fds, sharp_model) << "\n"; // setting refinement for each grid grid_classic.setSurplusRefinement(tolerance, TasGrid::refine_classic); grid_fds.setSurplusRefinement(tolerance, TasGrid::refine_fds); } // Repeat the example using construction auto vector_model = [=](std::vector const &x, std::vector &y, size_t tid)-> void{ y.resize(1); sharp_model(x.data(), y.data(), tid); }; // reset the grids grid_classic = TasGrid::makeLocalPolynomialGrid(num_inputs, 1, 2, order, TasGrid::rule_localp); grid_fds = TasGrid::copyGrid(grid_classic); // setup the top rows of the output table cout << "\nUsing construction:\n" << setw(22) << "classic" << setw(22) << "fds\n" << setw(8) << "points" << setw(14) << "error" << setw(8) << "points" << setw(14) << "error\n"; for(size_t budget = 50; budget < 800; budget += 100){ TasGrid::constructSurrogate(vector_model, budget, 1, 1, grid_classic, tolerance, TasGrid::refine_classic); TasGrid::constructSurrogate(vector_model, budget, 1, 1, grid_fds, tolerance, TasGrid::refine_fds); // output the grids and results at the current stage cout << setw(8) << grid_classic.getNumLoaded() << setw(14) << get_error(grid_classic, sharp_model) << setw(8) << grid_fds.getNumLoaded() << setw(14) << get_error(grid_fds, sharp_model) << "\n"; } // The FDS strategy does not win at every step of the way, but at the final // stage the FDS approach results in fewer nodes while keeping the error // at near the same magnitude #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_09 example] #endif } TASMANIAN-8.1/SparseGrids/Examples/example_sparse_grids_10.cpp000066400000000000000000000107571470551176200241270ustar00rootroot00000000000000 #include "Tasmanian.hpp" #include using namespace std; /*! * \internal * \file example_sparse_grids_10.cpp * \brief Examples for the Tasmanian Sparse Grid module. * \author Miroslav Stoyanov * \ingroup TasmanianSGExamples * * Tasmanian Sparse Grids Example 10. * \endinternal */ /*! * \ingroup TasmanianSGExamples * \addtogroup TasmanianSGExamples10 Tasmanian Sparse Grids module, example 10 * * \par Example 10 * Local polynomial vs. Wavelet grids. */ /*! * \ingroup TasmanianSGExamples10 * \brief Sparse Grids Example 10: local polynomial vs. wavelet grids * * Wavelet basis has a number of desirable properties compared to the simple local polynomials, * most notably, the basis coefficients are much sharper estimates of the local approximation * error. In an adaptive refinement context, this often leads to a decrease in the total * number of nodes. However, the wavelets also have large Lebesgue constant especially * around the boundary, which can have the converse effect. * * \snippet SparseGrids/Examples/example_sparse_grids_10.cpp SG_Example_10 example */ void sparse_grids_example_10(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_10 example] #endif cout << "\n---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(4); cout << "Example 10: comparison between local polynomial and wavelet grids\n\n"; int const num_inputs = 2; // using random points to test the error int const num_test_points = 1000; std::vector test_points(num_test_points * num_inputs); std::minstd_rand park_miller(42); std::uniform_real_distribution domain(-1.0, 1.0); for(auto &t : test_points) t = domain(park_miller); // computes the error between the gird surrogate model and the actual model // using the test points, finds the largest absolute error auto get_error = [&](TasGrid::TasmanianSparseGrid const &grid, std::function model)-> double{ std::vector grid_result; grid.evaluateBatch(test_points, grid_result); double err = 0.0; for(int i=0; i void{ y[0] = x[0] / (1.0 + 100.0 * std::exp(-10.0 * x[1])); }; // using order 1 int const order = 1; auto grid_poly = TasGrid::makeLocalPolynomialGrid(num_inputs, 1, 3, order, TasGrid::rule_localp); auto grid_wavelet = TasGrid::makeWaveletGrid(num_inputs, 1, 1, order); // setup the top rows of the output table cout << "Using batch refinement:\n" << setw(22) << "polynomial" << setw(22) << "wavelet\n" << setw(8) << "points" << setw(14) << "error" << setw(8) << "points" << setw(14) << "error\n"; double const tolerance = 1.E-5; while((grid_poly.getNumNeeded() > 0) || (grid_wavelet.getNumNeeded() > 0)){ TasGrid::loadNeededValues(sharp_model, grid_poly, 4); TasGrid::loadNeededValues(sharp_model, grid_wavelet, 4); // output the grids and results at the current stage cout << setw(8) << grid_poly.getNumLoaded() << setw(14) << get_error(grid_poly, sharp_model) << setw(8) << grid_wavelet.getNumLoaded() << setw(14) << get_error(grid_wavelet, sharp_model) << "\n"; // setting refinement for each grid grid_poly.setSurplusRefinement(tolerance, TasGrid::refine_fds); grid_wavelet.setSurplusRefinement(tolerance, TasGrid::refine_fds); } // Compared to local polynomial coefficients, the coefficients of the Wavelet basis // are a much sharper estimate of the local error, hence, wavelet based refinement // can result in approximation with significantly fewer nodes. // However, wavelets have larger Lebesgue constant (especially around the boundary) // and thus do not always outperform local polynomials. cout << "\n"; #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_10 example] #endif } TASMANIAN-8.1/SparseGrids/Examples/example_sparse_grids_11.cpp000066400000000000000000000112551470551176200241220ustar00rootroot00000000000000 #include "Tasmanian.hpp" #include using namespace std; /*! * \internal * \file example_sparse_grids_11.cpp * \brief Examples for the Tasmanian Sparse Grid module. * \author Miroslav Stoyanov * \ingroup TasmanianSGExamples * * Tasmanian Sparse Grids Example 11. * \endinternal */ /*! * \ingroup TasmanianSGExamples * \addtogroup TasmanianSGExamples11 Tasmanian Sparse Grids module, example 11 * * \par Example 11 * Constructing a grid from unstructured data. */ /*! * \ingroup TasmanianSGExamples11 * \brief Sparse Grids Example 11: Unstructured data * * Sparse grid approximation (or surrogates) can be constructed from a set of points * not necessarily aligned to the points on the grid, using a least-squares fit. * - the fit will not interpolate the data, i.e., there will be a difference between * the surrogate and the data at each point * - the overall accuracy will be lower and more points are needed to reach the same * accuracy as in the structured case, the fit should be used when the model * cannot be sampled exactly at the sparse grid points * - solving the fit requires the solution to a system of linear equations and * uses significant amount of flops and memory, at the minimum BLAS must be enabled * but GPU acceleration is preferable with the MAGMA library which provides * advanced out-of-core methods * * \snippet SparseGrids/Examples/example_sparse_grids_11.cpp SG_Example_11 example */ void sparse_grids_example_11(){ #ifndef __TASMANIAN_DOXYGEN_SKIP //! [SG_Example_11 example] #endif cout << "\n---------------------------------------------------------------------------------------------------\n"; cout << std::scientific; cout.precision(4); cout << "Example 11: construction using unstructured data\n\n"; int const num_inputs = 2; // using random points to test the error int const num_test_points = 1000; std::vector test_points(num_test_points * num_inputs); std::minstd_rand park_miller(42); std::uniform_real_distribution domain(-1.0, 1.0); for(auto &t : test_points) t = domain(park_miller); // computes the error between the gird surrogate model and the actual model // using the test points, finds the largest absolute error auto get_error = [&](TasGrid::TasmanianSparseGrid const &grid, std::function model)-> double{ std::vector grid_result; grid.evaluateBatch(test_points, grid_result); double err = 0.0; for(int i=0; i void{ y[0] = std::exp(-x[0]*x[0] -x[1]-x[1]); }; auto grid = TasGrid::makeGlobalGrid(num_inputs, 1, 4, TasGrid::type_level, TasGrid::rule_clenshawcurtis); // generate random data for the inputs, and compute the corresponding outputs int const num_data_points = 2000; std::vector data_input(num_inputs * num_data_points); std::vector data_output(num_data_points); for(auto &d : data_input) d = domain(park_miller); for(int i=0; i()), using_dynamic_construction(false){} TasmanianSparseGrid::TasmanianSparseGrid(const TasmanianSparseGrid &source) : acceleration(Utils::make_unique()), using_dynamic_construction(false){ copyGrid(&source); } TasmanianSparseGrid& TasmanianSparseGrid::operator=(TasmanianSparseGrid const &source){ copyGrid(&source); return *this; } void TasmanianSparseGrid::clear(){ base = std::unique_ptr(); domain_transform_a = std::vector(); domain_transform_b = std::vector(); conformal_asin_power = std::vector(); llimits = std::vector(); using_dynamic_construction = false; #ifdef Tasmanian_ENABLE_GPU acc_domain.reset(); #endif // Tasmanian_ENABLE_GPU } void TasmanianSparseGrid::write(const char *filename, bool binary) const{ std::ofstream ofs; if (binary == mode_binary){ ofs.open(filename, std::ios::out | std::ios::binary); }else{ ofs.open(filename); } if (!ofs.good()) throw std::runtime_error(std::string("ERROR: occurred when trying to write to file: ") + filename); write(ofs, binary); ofs.close(); } void TasmanianSparseGrid::read(const char *filename){ std::ifstream ifs; char TSG[3]; bool binary_format = mode_ascii; ifs.open(filename, std::ios::in | std::ios::binary); if (!ifs.good()) throw std::runtime_error(std::string("ERROR: occurred when trying to open file: ") + filename); ifs.read(TSG, 3 * sizeof(char)); if ((TSG[0] == 'T') && (TSG[1] == 'S') && (TSG[2] == 'G')){ binary_format = mode_binary; } ifs.close(); if (binary_format == mode_binary){ ifs.open(filename, std::ios::in | std::ios::binary); }else{ ifs.open(filename); } if (!ifs.good()) throw std::runtime_error(std::string("ERROR: occurred when trying to open file: ") + filename); read(ifs, binary_format); ifs.close(); } void TasmanianSparseGrid::write(std::ostream &ofs, bool binary) const{ if (binary == mode_binary){ writeBinary(ofs); }else{ writeAscii(ofs); } } void TasmanianSparseGrid::read(std::istream &ifs, bool binary){ if (binary == mode_binary){ readBinary(ifs); }else{ readAscii(ifs); } } void TasmanianSparseGrid::makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, const int *anisotropic_weights, double alpha, double beta, const char* custom_filename, const int *level_limits){ makeGlobalGrid(dimensions, outputs, depth, type, rule, Utils::copyArray(anisotropic_weights, (OneDimensionalMeta::isTypeCurved(type)) ? 2*dimensions : dimensions), alpha, beta, custom_filename, Utils::copyArray(level_limits, dimensions)); } void TasmanianSparseGrid::makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, const std::vector &anisotropic_weights, double alpha, double beta, const char* custom_filename, const std::vector &level_limits){ if (dimensions < 1) throw std::invalid_argument("ERROR: makeGlobalGrid() requires positive dimensions"); if (outputs < 0) throw std::invalid_argument("ERROR: makeGlobalGrid() requires non-negative outputs"); if (depth < 0) throw std::invalid_argument("ERROR: makeGlobalGrid() requires non-negative depth"); if (!OneDimensionalMeta::isGlobal(rule)) throw std::invalid_argument("ERROR: makeGlobalGrid() requires a global rule"); if ((rule == rule_customtabulated) && (custom_filename == 0)) throw std::invalid_argument("ERROR: makeGlobalGrid() with custom tabulated rule requires a filename"); size_t expected_aw_size = (OneDimensionalMeta::isTypeCurved(type)) ? 2*dimensions : dimensions; if ((!anisotropic_weights.empty()) && (anisotropic_weights.size() != expected_aw_size)) throw std::invalid_argument("ERROR: makeGlobalGrid() requires anisotropic_weights with either 0 or dimenions entries"); if ((!level_limits.empty()) && (level_limits.size() != (size_t) dimensions)) throw std::invalid_argument("ERROR: makeGlobalGrid() requires level_limits with either 0 or dimensions entries"); clear(); llimits = level_limits; base = Utils::make_unique(acceleration.get(), dimensions, outputs, depth, type, rule, anisotropic_weights, alpha, beta, custom_filename, llimits); } void TasmanianSparseGrid::makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, CustomTabulated &&crule, const int *anisotropic_weights, const int *level_limits){ makeGlobalGrid(dimensions, outputs, depth, type, std::move(crule), Utils::copyArray(anisotropic_weights, (OneDimensionalMeta::isTypeCurved(type)) ? 2*dimensions : dimensions), Utils::copyArray(level_limits, dimensions)); } void TasmanianSparseGrid::makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, CustomTabulated &&rule, std::vector const &anisotropic_weights, std::vector const &level_limits){ if (dimensions < 1) throw std::invalid_argument("ERROR: makeGlobalGrid() requires positive dimensions"); if (outputs < 0) throw std::invalid_argument("ERROR: makeGlobalGrid() requires non-negative outputs"); if (depth < 0) throw std::invalid_argument("ERROR: makeGlobalGrid() requires non-negative depth"); size_t expected_aw_size = (OneDimensionalMeta::isTypeCurved(type)) ? 2*dimensions : dimensions; if ((!anisotropic_weights.empty()) && (anisotropic_weights.size() != expected_aw_size)) throw std::invalid_argument("ERROR: makeGlobalGrid() requires anisotropic_weights with either 0 or dimenions entries"); if ((!level_limits.empty()) && (level_limits.size() != (size_t) dimensions)) throw std::invalid_argument("ERROR: makeGlobalGrid() requires level_limits with either 0 or dimensions entries"); clear(); llimits = level_limits; base = Utils::make_unique(acceleration.get(), dimensions, outputs, depth, type, std::move(rule), anisotropic_weights, llimits); } void TasmanianSparseGrid::makeSequenceGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, const int *anisotropic_weights, const int *level_limits){ makeSequenceGrid(dimensions, outputs, depth, type, rule, Utils::copyArray(anisotropic_weights, (OneDimensionalMeta::isTypeCurved(type)) ? 2*dimensions : dimensions), Utils::copyArray(level_limits, dimensions)); } void TasmanianSparseGrid::makeSequenceGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, const std::vector &anisotropic_weights, const std::vector &level_limits){ if (dimensions < 1) throw std::invalid_argument("ERROR: makeSequenceGrid() requires positive dimensions"); if (outputs < 0) throw std::invalid_argument("ERROR: makeSequenceGrid() requires non-negative outputs"); if (depth < 0) throw std::invalid_argument("ERROR: makeSequenceGrid() requires non-negative depth"); if (!OneDimensionalMeta::isSequence(rule)){ std::string message = "ERROR: makeSequenceGrid() is called with rule: " + IO::getRuleString(rule) + ", which is not a sequence rule"; throw std::invalid_argument(message); } size_t expected_aw_size = (OneDimensionalMeta::isTypeCurved(type)) ? 2*dimensions : dimensions; if ((!anisotropic_weights.empty()) && (anisotropic_weights.size() != expected_aw_size)) throw std::invalid_argument("ERROR: makeSequenceGrid() requires anisotropic_weights with either 0 or dimensions entries"); if ((!level_limits.empty()) && (level_limits.size() != (size_t) dimensions)) throw std::invalid_argument("ERROR: makeSequenceGrid() requires level_limits with either 0 or dimensions entries"); clear(); llimits = level_limits; base = (outputs == 0) ? Utils::make_unique(acceleration.get(), dimensions, depth, type, rule, anisotropic_weights, llimits) : Utils::make_unique(acceleration.get(), dimensions, outputs, depth, type, rule, anisotropic_weights, llimits); } void TasmanianSparseGrid::makeLocalPolynomialGrid(int dimensions, int outputs, int depth, int order, TypeOneDRule rule, const int *level_limits){ makeLocalPolynomialGrid(dimensions, outputs, depth, order, rule, Utils::copyArray(level_limits, dimensions)); } void TasmanianSparseGrid::makeLocalPolynomialGrid(int dimensions, int outputs, int depth, int order, TypeOneDRule rule, const std::vector &level_limits){ if (dimensions < 1) throw std::invalid_argument("ERROR: makeLocalPolynomialGrid() requires positive dimensions"); if (outputs < 0) throw std::invalid_argument("ERROR: makeLocalPolynomialGrid() requires non-negative outputs"); if (depth < 0) throw std::invalid_argument("ERROR: makeLocalPolynomialGrid() requires non-negative depth"); if (order < -1){ std::string message = "ERROR: makeLocalPolynomialGrid() is called with order: " + std::to_string(order) + ", but the order cannot be less than -1."; throw std::invalid_argument(message); } if (!OneDimensionalMeta::isLocalPolynomial(rule)){ std::string message = "ERROR: makeLocalPolynomialGrid() is called with rule: " + IO::getRuleString(rule) + ", which is not a local polynomial rule"; throw std::invalid_argument(message); } if ((!level_limits.empty()) && (level_limits.size() != (size_t) dimensions)) throw std::invalid_argument("ERROR: makeLocalPolynomialGrid() requires level_limits with either 0 or dimensions entries"); clear(); llimits = level_limits; base = Utils::make_unique(acceleration.get(), dimensions, outputs, depth, order, rule, llimits); } void TasmanianSparseGrid::makeWaveletGrid(int dimensions, int outputs, int depth, int order, const int *level_limits){ makeWaveletGrid(dimensions, outputs, depth, order, Utils::copyArray(level_limits, dimensions)); } void TasmanianSparseGrid::makeWaveletGrid(int dimensions, int outputs, int depth, int order, const std::vector &level_limits){ if (dimensions < 1) throw std::invalid_argument("ERROR: makeWaveletGrid() requires positive dimensions"); if (outputs < 0) throw std::invalid_argument("ERROR: makeWaveletGrid() requires non-negative outputs"); if (depth < 0) throw std::invalid_argument("ERROR: makeWaveletGrid() requires non-negative depth"); if ((order != 1) && (order != 3)){ std::string message = "ERROR: makeWaveletGrid() is called with order: " + std::to_string(order) + ", but wavelets are implemented only for orders 1 and 3."; throw std::invalid_argument(message); } if ((!level_limits.empty()) && (level_limits.size() != (size_t) dimensions)) throw std::invalid_argument("ERROR: makeWaveletGrid() requires level_limits with either 0 or dimensions entries"); clear(); llimits = level_limits; base = Utils::make_unique(acceleration.get(), dimensions, outputs, depth, order, llimits); } void TasmanianSparseGrid::makeFourierGrid(int dimensions, int outputs, int depth, TypeDepth type, const int* anisotropic_weights, const int* level_limits){ makeFourierGrid(dimensions, outputs, depth, type, Utils::copyArray(anisotropic_weights, (OneDimensionalMeta::isTypeCurved(type)) ? 2*dimensions : dimensions), Utils::copyArray(level_limits, dimensions)); } void TasmanianSparseGrid::makeFourierGrid(int dimensions, int outputs, int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ if (dimensions < 1) throw std::invalid_argument("ERROR: makeFourierGrid() requires positive dimensions"); if (outputs < 0) throw std::invalid_argument("ERROR: makeFourierGrid() requires non-negative outputs"); if (depth < 0) throw std::invalid_argument("ERROR: makeFourierGrid() requires non-negative depth"); size_t expected_aw_size = (OneDimensionalMeta::isTypeCurved(type)) ? 2*dimensions : dimensions; if ((!anisotropic_weights.empty()) && (anisotropic_weights.size() != expected_aw_size)) throw std::invalid_argument("ERROR: makeFourierGrid() requires anisotropic_weights with either 0 or dimensions entries"); if ((!level_limits.empty()) && (level_limits.size() != (size_t) dimensions)) throw std::invalid_argument("ERROR: makeFourierGrid() requires level_limits with either 0 or dimensions entries"); clear(); llimits = level_limits; base = Utils::make_unique(acceleration.get(), dimensions, outputs, depth, type, anisotropic_weights, llimits); } void TasmanianSparseGrid::copyGrid(const TasmanianSparseGrid *source, int outputs_begin, int outputs_end){ if (outputs_end == -1) outputs_end = source->getNumOutputs(); clear(); if (!source->empty()){ if (source->isGlobal()){ base = Utils::make_unique(acceleration.get(), source->get(), outputs_begin, outputs_end); }else if (source->isLocalPolynomial()){ base = Utils::make_unique(acceleration.get(), source->get(), outputs_begin, outputs_end); }else if (source->isSequence()){ base = Utils::make_unique(acceleration.get(), source->get(), outputs_begin, outputs_end); }else if (source->isFourier()){ base = Utils::make_unique(acceleration.get(), source->get(), outputs_begin, outputs_end); }else if (source->isWavelet()){ base = Utils::make_unique(acceleration.get(), source->get(), outputs_begin, outputs_end); } } if (source->domain_transform_a.size() > 0){ setDomainTransform(source->domain_transform_a, source->domain_transform_b); } conformal_asin_power = source->conformal_asin_power; llimits = source->llimits; using_dynamic_construction = source->using_dynamic_construction; } void TasmanianSparseGrid::updateGlobalGrid(int depth, TypeDepth type, const int *anisotropic_weights, const int *level_limits){ if (empty()) throw std::runtime_error("ERROR: updateGlobalGrid() called, but the grid is empty"); updateGlobalGrid(depth, type, Utils::copyArray(anisotropic_weights, (OneDimensionalMeta::isTypeCurved(type)) ? 2*getNumDimensions() : getNumDimensions()), Utils::copyArray(level_limits, getNumDimensions())); } void TasmanianSparseGrid::updateGlobalGrid(int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ updateGrid(depth, type, anisotropic_weights, level_limits); } void TasmanianSparseGrid::updateSequenceGrid(int depth, TypeDepth type, const int *anisotropic_weights, const int *level_limits){ if (empty()) throw std::runtime_error("ERROR: updateSequenceGrid called, but the grid is empty"); updateSequenceGrid(depth, type, Utils::copyArray(anisotropic_weights, (OneDimensionalMeta::isTypeCurved(type)) ? 2*getNumDimensions() : getNumDimensions()), Utils::copyArray(level_limits, getNumDimensions())); } void TasmanianSparseGrid::updateSequenceGrid(int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ updateGrid(depth, type, anisotropic_weights, level_limits); } void TasmanianSparseGrid::updateFourierGrid(int depth, TypeDepth type, const int *anisotropic_weights, const int *level_limits){ updateGrid(depth, type, anisotropic_weights, level_limits); } void TasmanianSparseGrid::updateFourierGrid(int depth, TypeDepth type, std::vector const &anisotropic_weights, std::vector const &level_limits){ updateGrid(depth, type, anisotropic_weights, level_limits); } void TasmanianSparseGrid::updateGrid(int depth, TypeDepth type, const int *anisotropic_weights, const int *level_limits){ if (empty()) throw std::runtime_error("ERROR: updateGrid() called, but the grid is empty"); updateGrid(depth, type, Utils::copyArray(anisotropic_weights, (OneDimensionalMeta::isTypeCurved(type)) ? 2*getNumDimensions() : getNumDimensions()), Utils::copyArray(level_limits, getNumDimensions())); } void TasmanianSparseGrid::updateGrid(int depth, TypeDepth type, std::vector const &anisotropic_weights, std::vector const &level_limits){ if (empty()) throw std::runtime_error("ERROR: updateGrid() called, but the grid is empty"); int dims = base->getNumDimensions(); if (depth < 0) throw std::invalid_argument("ERROR: cannot update with a negative depth"); size_t expected_aw_size = (OneDimensionalMeta::isTypeCurved(type)) ? 2*dims : dims; if (not anisotropic_weights.empty() and anisotropic_weights.size() != expected_aw_size) throw std::invalid_argument("ERROR: in updateGrid() anisotropic_weights must be either empty or has size equal to dimenions or twice dimenions based on the type of the update."); if (not level_limits.empty() and level_limits.size() != (size_t) dims) throw std::invalid_argument("ERROR: in updateGrid() level_limits must be either empty or must have size equal to the number of dimensions"); if (not level_limits.empty()) llimits = level_limits; // if level_limits is empty, use the existing llimits (if any) if (isGlobal()){ get()->updateGrid(depth, type, anisotropic_weights, llimits); }else if (isSequence()){ get()->updateGrid(depth, type, anisotropic_weights, llimits); }else if (isFourier()){ get()->updateGrid(depth, type, anisotropic_weights, llimits); }else{ throw std::runtime_error("ERROR: an update operation can be performed only on Global, Sequence and Fourier grids."); } } TypeOneDRule TasmanianSparseGrid::getRule() const{ return (base) ? base->getRule() : rule_none; } const char* TasmanianSparseGrid::getCustomRuleDescription() const{ return (isGlobal()) ? get()->getCustomRuleDescription() : ""; } void TasmanianSparseGrid::getLoadedPoints(double *x) const{ base->getLoadedPoints(x); formTransformedPoints(base->getNumLoaded(), x); } void TasmanianSparseGrid::getNeededPoints(double *x) const{ base->getNeededPoints(x); formTransformedPoints(base->getNumNeeded(), x); } void TasmanianSparseGrid::getPoints(double *x) const{ base->getPoints(x); formTransformedPoints(base->getNumPoints(), x); } void TasmanianSparseGrid::getQuadratureWeights(double *weights) const{ base->getQuadratureWeights(weights); mapConformalWeights(base->getNumDimensions(), base->getNumPoints(), weights); if (domain_transform_a.size() != 0){ double scale = getQuadratureScale(base->getNumDimensions(), base->getRule()); #pragma omp parallel for schedule(static) for(int i=0; i TasmanianSparseGrid::getInterpolationWeights(std::vector const &x) const{ std::vector w; getInterpolationWeights(x, w); return w; } void TasmanianSparseGrid::getInterpolationWeights(const std::vector &x, std::vector &weights) const{ if (x.size() != (size_t) base->getNumDimensions()) throw std::runtime_error("ERROR: getInterpolationWeights() incorrect size of x, must be same as getNumDimensions()"); weights.resize((size_t) getNumPoints()); getInterpolationWeights(x.data(), weights.data()); } void TasmanianSparseGrid::getInterpolationWeights(const double x[], double weights[]) const{ Data2D x_tmp; base->getInterpolationWeights(formCanonicalPoints(x, x_tmp, 1), weights); } std::vector TasmanianSparseGrid::getDifferentiationWeights(std::vector const &x) const{ std::vector w; getDifferentiationWeights(x, w); return w; } void TasmanianSparseGrid::getDifferentiationWeights(const std::vector &x, std::vector &weights) const{ if (x.size() != (size_t) base->getNumDimensions()) throw std::runtime_error("ERROR: getDifferentiationWeights() incorrect size of x, must be same as getNumDimensions()"); weights.resize((size_t) getNumPoints() * (size_t) getNumDimensions()); getDifferentiationWeights(x.data(), weights.data()); } void TasmanianSparseGrid::getDifferentiationWeights(const double x[], double weights[]) const{ // See differentiate() for how the domain transforms are taken into consideration. Data2D x_tmp; // Jacobian of f(.) at g(x). base->getDifferentiationWeights(formCanonicalPoints(x, x_tmp, 1), weights); // Jacobian of f(g(.)) at x. if (not domain_transform_a.empty()) { int num_dimensions = getNumDimensions(); int num_points = getNumPoints(); std::vector jacobian_g_diag = diffCanonicalTransform(); for(int i=0; iloadNeededValues(vals); } void TasmanianSparseGrid::loadNeededValues(const std::vector &vals){ size_t nump = (size_t) base->getNumNeeded(); if (nump == 0) nump = (size_t) base->getNumPoints(); nump *= (size_t) base->getNumOutputs(); if (vals.size() != nump) throw std::runtime_error("ERROR: loadNeededPoints() given the wrong number of inputs, should be getNumNeeded() * getNumOutputs() or (if getNumNeeded() == 0) getNumPoints() * getNumOutputs()"); loadNeededValues(vals.data()); } void TasmanianSparseGrid::evaluate(const double x[], double y[]) const{ Data2D x_tmp; base->evaluate(formCanonicalPoints(x, x_tmp, 1), y); } template void TasmanianSparseGrid::evaluateBatch(const std::vector &x, std::vector &y) const{ if (empty()) return; // should probably throw int num_outputs = getNumOutputs(); size_t num_x = x.size() / getNumDimensions(); y.resize(num_outputs * num_x); evaluateBatch(x.data(), (int) num_x, y.data()); } template void TasmanianSparseGrid::evaluateBatch(const std::vector &x, std::vector &y) const; template void TasmanianSparseGrid::evaluateBatch(const std::vector &x, std::vector &y) const; void TasmanianSparseGrid::evaluateBatch(const double x[], int num_x, double y[]) const{ Data2D x_tmp; base->evaluateBatch(formCanonicalPoints(x, x_tmp, num_x), num_x, y); } #ifdef Tasmanian_ENABLE_GPU void TasmanianSparseGrid::evaluateBatch(const float x[], int num_x, float y[]) const{ if (!( (getAccelerationType() == accel_gpu_cuda) || (getAccelerationType() == accel_gpu_magma) )) throw std::runtime_error("ERROR: batch evaluations in single precision require CUDA or MAGMA acceleration to be enabled"); Data2D x_tmp; float const *x_canonical = formCanonicalPoints(x, x_tmp, num_x); acceleration->setDevice(); GpuVector gpu_x(acceleration.get(), getNumDimensions(), num_x, x_canonical), gpu_result(acceleration.get(), num_x, getNumOutputs()); base->evaluateBatchGPU(gpu_x.data(), num_x, gpu_result.data()); gpu_result.unload(acceleration.get(), y); } template void TasmanianSparseGrid::evaluateBatchGPU(const FloatType gpu_x[], int cpu_num_x, FloatType gpu_y[]) const{ if (not acceleration->on_gpu()) throw std::runtime_error("ERROR: evaluateBatchGPU() requires that a cuda gpu acceleration is enabled."); acceleration->setDevice(); GpuVector gpu_temp_x; base->evaluateBatchGPU(formCanonicalPointsGPU(gpu_x, cpu_num_x, gpu_temp_x), cpu_num_x, gpu_y); } #else template void TasmanianSparseGrid::evaluateBatchGPU(const FloatType[], int, FloatType[]) const{ throw std::runtime_error("ERROR: batch evaluations GPU to GPU require Tasmanian_ENABLE_CUDA or Tasmanian_ENABLE_HIP"); } void TasmanianSparseGrid::evaluateBatch(const float[], int, float[]) const{ throw std::runtime_error("ERROR: batch evaluations in single precision require Tasmanian_ENABLE_CUDA or Tasmanian_ENABLE_HIP"); } #endif template void TasmanianSparseGrid::evaluateBatchGPU(const float[], int, float[]) const; template void TasmanianSparseGrid::evaluateBatchGPU(const double[], int, double[]) const; void TasmanianSparseGrid::integrate(double q[]) const{ if (conformal_asin_power.size() != 0){ int num_points = base->getNumPoints(); std::vector correction(num_points, 1.0); mapConformalWeights(base->getNumDimensions(), num_points, correction.data()); base->integrate(q, correction.data()); }else{ base->integrate(q, 0); } if (domain_transform_a.size() != 0){ double scale = getQuadratureScale(base->getNumDimensions(), base->getRule()); for(int k=0; k x_tmp; // Jacobian of f(.) at g(x). base->differentiate(formCanonicalPoints(x, x_tmp, 1), jacobian); // Jacobian of f(g(.)) at x. if (not domain_transform_a.empty()) { int num_dimensions = getNumDimensions(); int num_outputs = getNumOutputs(); std::vector jacobian_g_diag = diffCanonicalTransform(); for(int j=0; j &x, std::vector &y) const{ if (x.size() != (size_t) getNumDimensions()) throw std::runtime_error("ERROR: in evaluate() x must match getNumDimensions()"); y.resize((size_t) getNumOutputs()); evaluate(x.data(), y.data()); } void TasmanianSparseGrid::integrate(std::vector &q) const{ size_t num_outputs = getNumOutputs(); q.resize(num_outputs); integrate(q.data()); } void TasmanianSparseGrid::differentiate(std::vector const &x, std::vector &jacobian) const { size_t num_outputs = getNumOutputs(); size_t num_dimensions = getNumDimensions(); jacobian.resize(num_outputs * num_dimensions); differentiate(x.data(), jacobian.data()); } void TasmanianSparseGrid::setDomainTransform(const double a[], const double b[]){ if (empty()) throw std::runtime_error("ERROR: cannot call setDomainTransform on uninitialized grid!"); int num_dimensions = base->getNumDimensions(); domain_transform_a.resize(num_dimensions); std::copy(a, a + num_dimensions, domain_transform_a.data()); domain_transform_b.resize(num_dimensions); std::copy(b, b + num_dimensions, domain_transform_b.data()); #ifdef Tasmanian_ENABLE_GPU acc_domain.reset(); #endif } bool TasmanianSparseGrid::isSetDomainTransfrom() const{ return (domain_transform_a.size() != 0); } void TasmanianSparseGrid::clearDomainTransform(){ domain_transform_a.resize(0); domain_transform_b.resize(0); #ifdef Tasmanian_ENABLE_GPU acc_domain.reset(); #endif } void TasmanianSparseGrid::getDomainTransform(double a[], double b[]) const{ if (empty() || (domain_transform_a.size() == 0)) throw std::runtime_error("ERROR: cannot call getDomainTransform on uninitialized grid or if no transform has been set!"); std::copy(domain_transform_a.begin(), domain_transform_a.end(), a); std::copy(domain_transform_b.begin(), domain_transform_b.end(), b); } void TasmanianSparseGrid::setDomainTransform(const std::vector &a, const std::vector &b){ if (empty()) throw std::runtime_error("ERROR: cannot call setDomainTransform on uninitialized grid!"); size_t num_dimensions = (size_t) base->getNumDimensions(); if ((a.size() != num_dimensions) || (b.size() != num_dimensions)){ std::string message = "ERROR: setDomainTransform() is called with a.size() = " + std::to_string(a.size()) + " and b.size() = " + std::to_string(b.size()) + ", but both should have length equal to getNumDimensions(), which is: " + std::to_string(num_dimensions); throw std::invalid_argument(message); } domain_transform_a = a; // copy assignment domain_transform_b = b; #ifdef Tasmanian_ENABLE_GPU acc_domain.reset(); #endif } void TasmanianSparseGrid::getDomainTransform(std::vector &a, std::vector &b) const{ a = domain_transform_a; // copy assignment b = domain_transform_b; } void TasmanianSparseGrid::mapCanonicalToTransformed(int num_dimensions, int num_points, TypeOneDRule rule, double x[]) const{ if ((rule == rule_gausslaguerre) || (rule == rule_gausslaguerreodd)){ // canonical (0, +infty) for(int i=0; i sqrt_b(num_dimensions); for(int j=0; j rate(num_dimensions); std::vector shift(num_dimensions); for(int j=0; j void TasmanianSparseGrid::mapTransformedToCanonical(int num_dimensions, int num_points, TypeOneDRule rule, FloatType x[]) const{ if ((rule == rule_gausslaguerre) || (rule == rule_gausslaguerreodd)){ // canonical (0, +infty) for(int i=0; i sqrt_b(num_dimensions); for(int j=0; j rate(num_dimensions); std::vector shift(num_dimensions); for(int j=0; j(int num_dimensions, int num_points, TypeOneDRule rule, float x[]) const; template void TasmanianSparseGrid::mapTransformedToCanonical(int num_dimensions, int num_points, TypeOneDRule rule, double x[]) const; double TasmanianSparseGrid::getQuadratureScale(int num_dimensions, TypeOneDRule rule) const{ double scale = 1.0; // gauss- (chebyshev1, chebyshev2, gegenbauer) are special case of jacobi // points and weight are computed differently for better stability // the transform is the same, just have to set the effective alpha/beta for each case if ((rule == rule_gausschebyshev1) || (rule == rule_gausschebyshev2) || (rule == rule_gaussgegenbauer) || (rule == rule_gaussjacobi) || (rule == rule_gausschebyshev1odd) || (rule == rule_gausschebyshev2odd) || (rule == rule_gaussgegenbauerodd) || (rule == rule_gaussjacobiodd)){ double alpha = ((rule == rule_gausschebyshev1) || (rule == rule_gausschebyshev1odd)) ? -0.5 : ((rule == rule_gausschebyshev2) || (rule == rule_gausschebyshev2odd)) ? 0.5 : get()->getAlpha(); double beta = ((rule == rule_gausschebyshev1) || (rule == rule_gausschebyshev1odd)) ? -0.5 : ((rule == rule_gausschebyshev2) || (rule == rule_gausschebyshev2odd)) ? 0.5 : ((rule == rule_gaussgegenbauer) || (rule == rule_gaussgegenbauerodd)) ? get()->getAlpha() : get()->getBeta(); for(int j=0; j()->getAlpha())); }else if ((rule == rule_gausshermite) || (rule == rule_gausshermiteodd)){ double power = -0.5 * (1.0 + get()->getAlpha()); for(int j=0; j const &truncation){ if (empty()) throw std::runtime_error("ERROR: cannot call setConformalTransformASIN on uninitialized grid!"); clearConformalTransform(); conformal_asin_power = truncation; } bool TasmanianSparseGrid::isSetConformalTransformASIN() const{ return (conformal_asin_power.size() != 0); } void TasmanianSparseGrid::clearConformalTransform(){ conformal_asin_power.clear(); } std::vector TasmanianSparseGrid::getConformalTransformASIN() const{ if (empty() || (conformal_asin_power.size() == 0)) throw std::runtime_error("ERROR: cannot call getDomainTransform on uninitialized grid or if no transform has been set!"); return conformal_asin_power; } void TasmanianSparseGrid::mapConformalCanonicalToTransformed(int num_dimensions, int num_points, double x[]) const{ if (conformal_asin_power.size() != 0){ // precompute constants, transform is sum exp(c_k + p_k * log(x)) std::vector> c(num_dimensions), p(num_dimensions); for(int j=0; j cm(num_dimensions, 0.0); for(int j=0; j xwrap(num_dimensions, x); for(int i=0; i 0.0) ? 1.0 : -1.0; double logx = std::log(std::abs(this_x[j])); this_x[j] = 0.0; for(int k=0; k<=conformal_asin_power[j]; k++){ this_x[j] += std::exp(c[j][k] + p[j][k] * logx); } this_x[j] *= sign / cm[j]; } } } } } template void TasmanianSparseGrid::mapConformalTransformedToCanonical(int num_dimensions, int num_points, Data2D &x) const{ if (conformal_asin_power.size() != 0){ // precompute constants, transform is sum exp(c_k + p_k * log(x)) std::vector> c(num_dimensions), p(num_dimensions), dc(num_dimensions), dp(num_dimensions); for(int j=0; j cm(num_dimensions, 0.0); for(int j=0; j 0.0) ? 1.0 : -1.0; this_x[j] = (FloatType) std::abs(this_x[j]); double b = this_x[j]; double logx = log(this_x[j]); double r = this_x[j]; double dr = 1.0; for(int k=1; k<=conformal_asin_power[j]; k++){ r += std::exp( c[j][k] + p[j][k] * logx); dr += std::exp(dc[j][k] + dp[j][k] * logx); } r /= cm[j]; r -= b; // transformed_x -b = 0 while(std::abs(r) > Maths::num_tol){ this_x[j] -= (FloatType) (r * cm[j] / dr); logx = std::log(std::abs(this_x[j])); r = this_x[j]; dr = 1.0; for(int k=1; k<=conformal_asin_power[j]; k++){ r += std::exp( c[j][k] + p[j][k] * logx); dr += std::exp(dc[j][k] + dp[j][k] * logx); } r /= cm[j]; r -= b; } this_x[j] *= (FloatType) sign; } } } } } template void TasmanianSparseGrid::mapConformalTransformedToCanonical(int num_dimensions, int num_points, Data2D &x) const; template void TasmanianSparseGrid::mapConformalTransformedToCanonical(int num_dimensions, int num_points, Data2D &x) const; void TasmanianSparseGrid::mapConformalWeights(int num_dimensions, int num_points, double weights[]) const{ if (conformal_asin_power.size() != 0){ // precompute constants, transform is sum exp(c_k + p_k * log(x)) Data2D x(num_dimensions, num_points); base->getPoints(x.getStrip(0)); std::vector> c(num_dimensions), p(num_dimensions); for(int j=0; j cm(num_dimensions); for(int j=0; j const FloatType* TasmanianSparseGrid::formCanonicalPoints(const FloatType *x, Data2D &x_temp, int num_x) const{ if ((domain_transform_a.size() != 0) || (conformal_asin_power.size() != 0)){ int num_dimensions = base->getNumDimensions(); x_temp = Data2D(num_dimensions, num_x, std::vector(x, x + Utils::size_mult(num_dimensions, num_x))); mapConformalTransformedToCanonical(num_dimensions, num_x, x_temp); if (domain_transform_a.size() != 0) mapTransformedToCanonical(num_dimensions, num_x, base->getRule(), x_temp.getStrip(0)); return x_temp.getStrip(0); }else{ return x; } } template const float* TasmanianSparseGrid::formCanonicalPoints(const float *x, Data2D &x_temp, int num_x) const; template const double* TasmanianSparseGrid::formCanonicalPoints(const double *x, Data2D &x_temp, int num_x) const; template std::vector TasmanianSparseGrid::diffCanonicalTransform() const { int num_dimensions = base->getNumDimensions(); std::vector jacobian_diag(num_dimensions, 1.0); if (conformal_asin_power.size() != 0) { throw std::runtime_error("ERROR: in diffCanonicalTransform() derivatives/Jacobians are not available for conformal mappings"); } if (domain_transform_a.size() != 0) { // Based on the logic in mapTransformedToCanonical(). These are all affine transforms. TypeOneDRule rule = base->getRule(); if (rule == rule_gausslaguerre or rule == rule_gausslaguerreodd) for(int j=0; jgetNumDimensions(), num_points, x); // internally switch based on the conformal transform if (domain_transform_a.size() != 0){ // check the basic domain mapCanonicalToTransformed(base->getNumDimensions(), num_points, base->getRule(), x); } } template const T* TasmanianSparseGrid::formCanonicalPointsGPU(const T *gpu_x, int num_x, GpuVector &gpu_x_temp) const{ if (!domain_transform_a.empty()){ if (!acc_domain) acc_domain = Utils::make_unique(acceleration.get(), domain_transform_a, domain_transform_b); acc_domain->getCanonicalPoints(isFourier(), gpu_x, num_x, gpu_x_temp); return gpu_x_temp.data(); }else{ return gpu_x; } } void TasmanianSparseGrid::setAnisotropicRefinement(TypeDepth type, int min_growth, int output, const int *level_limits){ if (using_dynamic_construction) throw std::runtime_error("ERROR: setAnisotropicRefinement() called before finishConstruction()"); if (empty()) throw std::runtime_error("ERROR: calling setAnisotropicRefinement() for a grid that has not been initialized"); setAnisotropicRefinement(type, min_growth, output, Utils::copyArray(level_limits, getNumDimensions())); } void TasmanianSparseGrid::setAnisotropicRefinement(TypeDepth type, int min_growth, int output, const std::vector &level_limits){ if (using_dynamic_construction) throw std::runtime_error("ERROR: setAnisotropicRefinement() called before finishConstruction()"); if (empty()) throw std::runtime_error("ERROR: calling setAnisotropicRefinement() for a grid that has not been initialized"); if (min_growth < 1) throw std::invalid_argument("ERROR: setAnisotropicRefinement() requires positive min_growth"); int dims = base->getNumDimensions(); int outs = base->getNumOutputs(); if (outs == 0) throw std::runtime_error("ERROR: calling setAnisotropicRefinement() for a grid that has no outputs"); if (base->getNumLoaded() == 0) throw std::runtime_error("ERROR: calling setAnisotropicRefinement() for a grid with no loaded values"); if ((output < -1) || (output >= outs)) throw std::invalid_argument("ERROR: calling setAnisotropicRefinement() with invalid output"); if ((!level_limits.empty()) && (level_limits.size() != (size_t) dims)) throw std::invalid_argument("ERROR: setAnisotropicRefinement() requires level_limits with either 0 or dimenions entries"); if (!level_limits.empty()) llimits = level_limits; if (isSequence()){ get()->setAnisotropicRefinement(type, min_growth, output, llimits); }else if (isGlobal()){ if (OneDimensionalMeta::isNonNested(get()->getRule())){ throw std::runtime_error("ERROR: setAnisotropicRefinement() called for a global grid with non-nested rule"); }else{ get()->setAnisotropicRefinement(type, min_growth, output, llimits); } }else if (isFourier()){ get()->setAnisotropicRefinement(type, min_growth, output, llimits); }else{ throw std::runtime_error("ERROR: setAnisotropicRefinement() called for a grid that is neither Sequence, nor Global with a sequence rule, nor Fourier"); } } void TasmanianSparseGrid::estimateAnisotropicCoefficients(TypeDepth type, int output, std::vector &weights) const{ if (empty()) throw std::runtime_error("ERROR: calling estimateAnisotropicCoefficients() for a grid that has not been initialized"); int outs = base->getNumOutputs(); if (outs == 0) throw std::runtime_error("ERROR: calling estimateAnisotropicCoefficients() for a grid that has no outputs"); if (base->getNumLoaded() == 0) throw std::runtime_error("ERROR: calling estimateAnisotropicCoefficients() for a grid with no loaded values"); if ((output < -1) || (output >= outs)) throw std::invalid_argument("ERROR: calling estimateAnisotropicCoefficients() with invalid output"); if (isSequence()){ get()->estimateAnisotropicCoefficients(type, output, weights); }else if (isGlobal()){ if (OneDimensionalMeta::isNonNested(get()->getRule())){ throw std::runtime_error("ERROR: estimateAnisotropicCoefficients called for a Global grid with non-nested rule"); }else{ get()->estimateAnisotropicCoefficients(type, output, weights); } }else if (isFourier()){ get()->estimateAnisotropicCoefficients(type, output, weights); }else{ throw std::runtime_error("ERROR: estimateAnisotropicCoefficients called for a grid that is neither Sequence nor Global with a sequence rule"); } } void TasmanianSparseGrid::setSurplusRefinement(double tolerance, int output, const int *level_limits){ if (empty()) throw std::runtime_error("ERROR: calling setSurplusRefinement() for a grid that has not been initialized"); setSurplusRefinement(tolerance, output, Utils::copyArray(level_limits, getNumDimensions())); } void TasmanianSparseGrid::setSurplusRefinement(double tolerance, int output, const std::vector &level_limits){ if (using_dynamic_construction) throw std::runtime_error("ERROR: setSurplusRefinement() called before finishConstruction()"); if (empty()) throw std::runtime_error("ERROR: calling setSurplusRefinement() for a grid that has not been initialized"); int dims = base->getNumDimensions(); int outs = base->getNumOutputs(); if (outs == 0) throw std::runtime_error("ERROR: calling setSurplusRefinement() for a grid that has no outputs"); if (base->getNumLoaded() == 0) throw std::runtime_error("ERROR: calling setSurplusRefinement() for a grid with no loaded values"); if ((output < -1) || (output >= outs)) throw std::invalid_argument("ERROR: calling setSurplusRefinement() with invalid output"); if (tolerance < 0.0) throw std::invalid_argument("ERROR: calling setSurplusRefinement() with invalid tolerance (must be non-negative)"); if ((!level_limits.empty()) && (level_limits.size() != (size_t) dims)) throw std::invalid_argument("ERROR: setSurplusRefinement() requires level_limits with either 0 or dimenions entries"); if (!level_limits.empty()) llimits = level_limits; if (isSequence()){ get()->setSurplusRefinement(tolerance, output, llimits); }else if (isGlobal()){ if (OneDimensionalMeta::isSequence(get()->getRule())){ get()->setSurplusRefinement(tolerance, output, llimits); }else{ throw std::runtime_error("ERROR: setSurplusRefinement called for a Global grid with non-sequence rule"); } }else{ throw std::runtime_error("ERROR: setSurplusRefinement(double, int) called for a grid that is neither Sequence nor Global with a sequence rule"); } } void TasmanianSparseGrid::setSurplusRefinement(double tolerance, TypeRefinement criteria, int output, const int *level_limits, const double *scale_correction){ if (using_dynamic_construction) throw std::runtime_error("ERROR: setSurplusRefinement() called before finishConstruction()"); if (empty()) throw std::runtime_error("ERROR: calling setSurplusRefinement() for a grid that has not been initialized"); int dims = base->getNumDimensions(); int outs = base->getNumOutputs(); if (outs == 0) throw std::runtime_error("ERROR: calling setSurplusRefinement() for a grid that has no outputs"); if (base->getNumLoaded() == 0) throw std::runtime_error("ERROR: calling setSurplusRefinement() for a grid with no loaded values"); if ((output < -1) || (output >= outs)) throw std::invalid_argument("ERROR: calling setSurplusRefinement() with invalid output"); if (isFourier()) throw std::runtime_error("ERROR: setSurplusRefinement(double, TypeRefinement) called for a Fourier grid."); if (tolerance < 0.0) throw std::invalid_argument("ERROR: calling setSurplusRefinement() with invalid tolerance (must be non-negative)"); if (level_limits != 0) // can only happen if calling directly with int*, the vector version always passes null for level_limits llimits = Utils::copyArray(level_limits, dims); // if level_limits is null, we want to keep llimits unchanged if (isLocalPolynomial()){ get()->setSurplusRefinement(tolerance, criteria, output, llimits, scale_correction); }else if (isWavelet()){ get()->setSurplusRefinement(tolerance, criteria, output, llimits); }else{ setSurplusRefinement(tolerance, output, std::vector()); // new level limits are already set above } } void TasmanianSparseGrid::setSurplusRefinement(double tolerance, TypeRefinement criteria, int output, const std::vector &level_limits, const std::vector &scale_correction){ if (empty()) throw std::runtime_error("ERROR: calling setSurplusRefinement() for a grid that has not been initialized"); int dims = base->getNumDimensions(); size_t nscale = (size_t) base->getNumNeeded(); if (output != -1) nscale *= (size_t) base->getNumOutputs(); if ((!level_limits.empty()) && (level_limits.size() != (size_t) dims)) throw std::invalid_argument("ERROR: setSurplusRefinement() requires level_limits with either 0 or dimenions entries"); if ((!scale_correction.empty()) && (scale_correction.size() != nscale)) throw std::invalid_argument("ERROR: setSurplusRefinement() incorrect size for scale_correction"); if (!level_limits.empty()) llimits = level_limits; setSurplusRefinement(tolerance, criteria, output, nullptr, (scale_correction.empty()) ? nullptr : scale_correction.data()); } void TasmanianSparseGrid::clearRefinement(){ if (!empty()) base->clearRefinement(); } void TasmanianSparseGrid::mergeRefinement(){ if (!empty()) base->mergeRefinement(); } void TasmanianSparseGrid::beginConstruction(){ if (empty()) throw std::runtime_error("ERROR: cannot start construction for an empty grid."); if (not using_dynamic_construction){ if (getNumLoaded() > 0) clearRefinement(); using_dynamic_construction = true; base->beginConstruction(); } } std::vector TasmanianSparseGrid::getCandidateConstructionPoints(TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ if (not using_dynamic_construction) throw std::runtime_error("ERROR: getCandidateConstructionPoints() called before beginConstruction()"); if (isLocalPolynomial() || isWavelet()) throw std::runtime_error("ERROR: getCandidateConstructionPoints() anisotropic version called for local polynomial grid"); size_t dims = (size_t) base->getNumDimensions(); if ((!level_limits.empty()) && (level_limits.size() != (size_t) dims)) throw std::invalid_argument("ERROR: getCandidateConstructionPoints() requires level_limits with either 0 or num-dimensions entries"); if ((type == type_curved) || (type == type_ipcurved) || (type == type_qpcurved)){ if (anisotropic_weights.size() != 2 * dims) throw std::invalid_argument("ERROR: getCandidateConstructionPoints() called with curved type and incorrect size for anisotropic_weights (must be twice the number of dimensions)"); }else{ if (anisotropic_weights.size() != dims) throw std::invalid_argument("ERROR: getCandidateConstructionPoints() called with incorrect size for anisotropic_weights (must match number of dimensions)"); } if (!level_limits.empty()) llimits = level_limits; std::vector x; if (isGlobal()){ x = get()->getCandidateConstructionPoints(type, anisotropic_weights, llimits); }else if (isSequence()){ x = get()->getCandidateConstructionPoints(type, anisotropic_weights, llimits); }else{ // Fourier x = get()->getCandidateConstructionPoints(type, anisotropic_weights, llimits); } formTransformedPoints((int) x.size() / getNumDimensions(), x.data()); return x; } std::vector TasmanianSparseGrid::getCandidateConstructionPoints(TypeDepth type, int output, const std::vector &level_limits){ if (not using_dynamic_construction) throw std::runtime_error("ERROR: getCandidateConstructionPoints() called before beginConstruction()"); if (isLocalPolynomial() || isWavelet()) throw std::runtime_error("ERROR: getCandidateConstructionPoints() anisotropic version called for local polynomial grid"); size_t dims = (size_t) base->getNumDimensions(); if ((!level_limits.empty()) && (level_limits.size() != dims)) throw std::invalid_argument("ERROR: getCandidateConstructionPoints() requires level_limits with either 0 or num-dimensions entries"); int outs = base->getNumOutputs(); if (outs == 0) throw std::runtime_error("ERROR: calling getCandidateConstructionPoints() for a grid that has no outputs"); if ((output < -1) || (output >= outs)) throw std::invalid_argument("ERROR: calling getCandidateConstructionPoints() with invalid output"); if (!level_limits.empty()) llimits = level_limits; std::vector x; if (isGlobal()){ x = get()->getCandidateConstructionPoints(type, output, llimits); }else if (isSequence()){ x = get()->getCandidateConstructionPoints(type, output, llimits); }else{ // Fourier x = get()->getCandidateConstructionPoints(type, output, llimits); } formTransformedPoints((int) x.size() / getNumDimensions(), x.data()); return x; } std::vector TasmanianSparseGrid::getCandidateConstructionPoints(double tolerance, TypeRefinement criteria, int output, const std::vector &level_limits, const std::vector &scale_correction){ if (not using_dynamic_construction) throw std::runtime_error("ERROR: getCandidateConstructionPoints() called before beginConstruction()"); if (!isLocalPolynomial() && !isWavelet()) throw std::runtime_error("ERROR: getCandidateConstructionPoints() surplus version called for non-local polynomial or wavelet grid"); size_t dims = (size_t) base->getNumDimensions(); if ((!level_limits.empty()) && (level_limits.size() != dims)) throw std::invalid_argument("ERROR: getCandidateConstructionPoints() requires level_limits with either 0 or num-dimensions entries"); int outs = base->getNumOutputs(); if (outs == 0) throw std::runtime_error("ERROR: calling getCandidateConstructionPoints() for a grid that has no outputs"); if ((output < -1) || (output >= outs)) throw std::invalid_argument("ERROR: calling getCandidateConstructionPoints() with invalid output"); if (!level_limits.empty()) llimits = level_limits; auto x = (isWavelet()) ? get()->getCandidateConstructionPoints(tolerance, criteria, output, llimits) : get()->getCandidateConstructionPoints(tolerance, criteria, output, llimits, ((scale_correction.empty()) ? nullptr : scale_correction.data())); formTransformedPoints((int) x.size() / getNumDimensions(), x.data()); return x; } void TasmanianSparseGrid::loadConstructedPoints(const std::vector &x, const std::vector &y){ int numx = (int) x.size() / base->getNumDimensions(); if (y.size() < Utils::size_mult(numx, base->getNumOutputs())) throw std::runtime_error("ERROR: loadConstructedPoint() called with incorrect size for y"); loadConstructedPoints(x.data(), numx, y.data()); } void TasmanianSparseGrid::loadConstructedPoints(const double x[], int numx, const double y[]){ if (not using_dynamic_construction) throw std::runtime_error("ERROR: loadConstructedPoint() called before beginConstruction()"); Data2D x_tmp; const double *x_canonical = formCanonicalPoints(x, x_tmp, numx); if (numx == 1) base->loadConstructedPoint(x_canonical, Utils::copyArray(y, getNumOutputs())); else base->loadConstructedPoint(x_canonical, numx, y); } void TasmanianSparseGrid::finishConstruction(){ if (using_dynamic_construction) base->finishConstruction(); using_dynamic_construction = false; } void TasmanianSparseGrid::removePointsByHierarchicalCoefficient(double tolerance, int output, const double *scale_correction){ if (!isLocalPolynomial()){ throw std::runtime_error("ERROR: removePointsBySurplus() called for a grid that is not Local Polynomial."); }else{ if (get()->removePointsByHierarchicalCoefficient(tolerance, output, scale_correction) == 0){ clear(); } } } void TasmanianSparseGrid::removePointsByHierarchicalCoefficient(int num_new_points, int output, const double *scale_correction){ if (!isLocalPolynomial()){ throw std::runtime_error("ERROR: removePointsBySurplus() called for a grid that is not Local Polynomial."); }else{ if (num_new_points == 0){ clear(); return; } get()->removePointsByHierarchicalCoefficient(num_new_points, output, scale_correction); } } void TasmanianSparseGrid::evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const{ Data2D x_tmp; base->evaluateHierarchicalFunctions(formCanonicalPoints(x, x_tmp, num_x), num_x, y); } void TasmanianSparseGrid::evaluateHierarchicalFunctions(const std::vector &x, std::vector &y) const{ if (empty()) throw std::runtime_error("ERROR: cannot call evaluateHierarchicalFunctions() on an empty grid"); int num_points = getNumPoints(); size_t num_x = x.size() / getNumDimensions(); size_t expected_size = num_points * num_x * (isFourier() ? 2 : 1); y.resize(expected_size); evaluateHierarchicalFunctions(x.data(), (int) num_x, y.data()); } template void TasmanianSparseGrid::evaluateHierarchicalFunctionsGPU(const T gpu_x[], int cpu_num_x, T gpu_y[]) const{ if (not AccelerationMeta::isAvailable(accel_gpu_cuda)) throw std::runtime_error("ERROR: evaluateHierarchicalFunctionsGPU() called, but the library was not compiled without Tasmanian_ENABLE_CUDA=ON and Tasmanian_ENABLE_HIP=ON"); if (not acceleration->on_gpu()) throw std::runtime_error("ERROR: evaluateHierarchicalFunctionsGPU() requires that a cuda gpu acceleration is enabled."); acceleration->setDevice(); GpuVector gpu_temp_x; base->evaluateHierarchicalFunctionsGPU(formCanonicalPointsGPU(gpu_x, cpu_num_x, gpu_temp_x), cpu_num_x, gpu_y); } template void TasmanianSparseGrid::evaluateSparseHierarchicalFunctionsGPU(const T gpu_x[], int cpu_num_x, int* &gpu_pntr, int* &gpu_indx, T* &gpu_vals, int &num_nz) const{ if (not AccelerationMeta::isAvailable(accel_gpu_cuda)) throw std::runtime_error("ERROR: evaluateSparseHierarchicalFunctionsGPU() called, but the library was not compiled without Tasmanian_ENABLE_CUDA=ON and Tasmanian_ENABLE_HIP=ON"); if (!isLocalPolynomial()) throw std::runtime_error("ERROR: evaluateSparseHierarchicalFunctionsGPU() is allowed only for local polynomial grid."); if (not acceleration->on_gpu()) throw std::runtime_error("ERROR: evaluateSparseHierarchicalFunctionsGPU() requires that a cuda gpu acceleration is enabled."); acceleration->setDevice(); GpuVector gpu_temp_x; const T *gpu_canonical_x = formCanonicalPointsGPU(gpu_x, cpu_num_x, gpu_temp_x); GpuVector vec_pntr, vec_indx; GpuVector vec_vals; get()->buildSparseBasisMatrixGPU(gpu_canonical_x, cpu_num_x, vec_pntr, vec_indx, vec_vals); num_nz = (int) vec_indx.size(); gpu_pntr = vec_pntr.eject(); gpu_indx = vec_indx.eject(); gpu_vals = vec_vals.eject(); } template void TasmanianSparseGrid::evaluateHierarchicalFunctionsGPU(float const gpu_x[], int cpu_num_x, float gpu_y[]) const; template void TasmanianSparseGrid::evaluateHierarchicalFunctionsGPU(double const gpu_x[], int cpu_num_x, double gpu_y[]) const; template void TasmanianSparseGrid::evaluateSparseHierarchicalFunctionsGPU(const float[], int, int*&, int*&, float*&, int&) const; template void TasmanianSparseGrid::evaluateSparseHierarchicalFunctionsGPU(const double[], int, int*&, int*&, double*&, int&) const; void TasmanianSparseGrid::evaluateSparseHierarchicalFunctions(const std::vector &x, std::vector &pntr, std::vector &indx, std::vector &vals) const{ if (!isLocalPolynomial() && !isWavelet()) throw std::runtime_error("ERROR: evaluateSparseHierarchicalFunctions() called for a grid that is neither local polynomial not wavelet"); int num_x = ((int) x.size()) / getNumDimensions(); Data2D x_tmp; const double *x_canonical = formCanonicalPoints(x.data(), x_tmp, num_x); if (isLocalPolynomial()){ get()->buildSpareBasisMatrix(x_canonical, num_x, 32, pntr, indx, vals); }else{ int num_points = base->getNumPoints(); std::vector dense_vals(((size_t) num_points) * ((size_t) num_x)); base->evaluateHierarchicalFunctions(x_canonical, num_x, dense_vals.data()); int num_nz = 0; for(int i=0; i x_tmp; const double *x_canonical = formCanonicalPoints(x, x_tmp, num_x); if (isLocalPolynomial()){ return get()->getSpareBasisMatrixNZ(x_canonical, num_x); }else if (isWavelet()){ int num_points = base->getNumPoints(); Data2D dense_vals(num_points, num_x); get()->evaluateHierarchicalFunctions(x_canonical, num_x, dense_vals.data()); return static_cast(dense_vals.getTotalEntries() - std::count(dense_vals.begin(), dense_vals.end(), 0.0)); }else if (empty()){ return 0; }else{ throw std::runtime_error("ERROR: evaluateSparseHierarchicalFunctionsGetNZ() called for a grid that is neither local polynomial not wavelet"); } } void TasmanianSparseGrid::evaluateSparseHierarchicalFunctionsStatic(const double x[], int num_x, int pntr[], int indx[], double vals[]) const{ if (empty()) return; Data2D x_tmp; const double *x_canonical = formCanonicalPoints(x, x_tmp, num_x); if (isLocalPolynomial()){ get()->buildSpareBasisMatrixStatic(x_canonical, num_x, 32, pntr, indx, vals); }else if (isWavelet()){ int num_points = base->getNumPoints(); Data2D dense_vals(num_points, num_x); base->evaluateHierarchicalFunctions(x_canonical, num_x, dense_vals.getStrip(0)); int num_nz = 0; for(int i=0; i TasmanianSparseGrid::getHierarchicalSupport() const{ std::vector support = (empty()) ? std::vector() : base->getSupport(); if (!domain_transform_a.empty()){ std::vector correction(domain_transform_a.size()); std::transform(domain_transform_a.begin(), domain_transform_a.end(), domain_transform_b.begin(), correction.begin(), [](double a, double b)->double{ return 0.5 * (b - a); }); for(auto is = support.begin(); is < support.end(); ){ for(auto c : correction) *is++ *= c; } } return support; } void TasmanianSparseGrid::setHierarchicalCoefficients(const std::vector &c){ size_t num_coeffs = Utils::size_mult(getNumOutputs(), getNumPoints()) * ((isFourier()) ? 2 : 1); if (c.size() != num_coeffs) throw std::runtime_error("ERROR: setHierarchicalCoefficients() called with wrong size of the coefficients."); setHierarchicalCoefficients(c.data()); } void TasmanianSparseGrid::integrateHierarchicalFunctions(double integrals[]) const{ if (empty()) throw std::runtime_error("ERROR: cannot compute the integrals for a basis in an empty grid."); base->integrateHierarchicalFunctions(integrals); if (domain_transform_a.size() != 0){ double scale = getQuadratureScale(base->getNumDimensions(), base->getRule()); for(int i=0; i TasmanianSparseGrid::getGlobalPolynomialSpace(bool interpolation) const{ if (isGlobal()){ return get()->getPolynomialSpace(interpolation); }else if (isSequence()){ return get()->getPolynomialSpace(interpolation); }else{ throw std::runtime_error("ERROR: getGlobalPolynomialSpace() called for a grid that is neither Global nor Sequence"); } } const double* TasmanianSparseGrid::getHierarchicalCoefficients() const{ if (isLocalPolynomial()){ return get()->getSurpluses(); }else if (isWavelet()){ return get()->getSurpluses(); }else if (isSequence()){ return get()->getSurpluses(); }else if (isGlobal()){ return get()->getLoadedValues(); }else if (isFourier()){ return get()->getFourierCoefs(); }else{ return nullptr; } } const int* TasmanianSparseGrid::getPointsIndexes() const{ if (empty()){ throw std::runtime_error("ERROR: getPointIndexes() called for a grid that has not been initialized"); }else{ return base->getPointIndexes(); } } const int* TasmanianSparseGrid::getNeededIndexes() const{ if (isLocalPolynomial()){ return get()->getNeededIndexes(); }else{ throw std::runtime_error("ERROR: getPointIndexes() called for a grid that is not Local Polynomial"); } } void TasmanianSparseGrid::printStats(std::ostream &os) const{ using std::setw; const int L1 = 20; os << '\n'; os << setw(L1) << "Grid Type:" << " "; if (isGlobal()) os << "Global"; if (isSequence()) os << "Sequence"; if (isLocalPolynomial()) os << "Local Polynomial"; if (isWavelet()) os << "Wavelets"; if (isFourier()) os << "Fourier"; if (!(isGlobal() || isSequence() || isLocalPolynomial() || isWavelet() || isFourier())) os << "none"; os << '\n'; os << setw(L1) << "Dimensions:" << " " << getNumDimensions() << '\n'; os << setw(L1) << "Outputs:" << " " << getNumOutputs() << '\n'; if (getNumOutputs() == 0){ os << setw(L1) << "Nodes:" << " " << getNumPoints() << '\n'; }else{ os << setw(L1) << "Loaded nodes:" << " " << getNumLoaded() << '\n'; os << setw(L1) << "Needed nodes:" << " " << getNumNeeded() << '\n'; } os << setw(L1) << "Rule:" << " " << OneDimensionalMeta::getHumanString(getRule()) << '\n'; if (getRule() == rule_customtabulated){ os << setw(L1) << "Description:" << " " << getCustomRuleDescription() << '\n'; } if (isSetDomainTransfrom()){ os << setw(L1) << "Domain:" << " Custom" << '\n'; }else{ os << setw(L1) << "Domain:" << " Canonical" << '\n'; } if (isGlobal()){ TypeOneDRule rr = getRule(); if ((rr == rule_gaussgegenbauer) || (rr == rule_gausslaguerre) || (rr == rule_gausshermite) || (rr == rule_gaussgegenbauerodd) || (rr == rule_gausshermiteodd) ){ os << setw(L1) << "Alpha:" << " " << getAlpha() << '\n'; } if (rr == rule_gaussjacobi){ os << setw(L1) << "Alpha:" << " " << getAlpha() << '\n'; os << setw(L1) << "Beta:" << " " << getBeta() << '\n'; } }else if (isSequence()){ // sequence rules are simple, nothing to specify here }else if (isLocalPolynomial()){ os << setw(L1) << "Order:" << " " << getOrder() << '\n'; }else if (isWavelet()){ os << setw(L1) << "Order:" << " " << getOrder() << '\n'; }else{ // empty grid, show nothing, just like the sequence grid } os << setw(L1) << "Acceleration:" << " " << AccelerationMeta::getIOAccelerationString(acceleration->mode) << '\n'; if (isLocalPolynomial() or isWavelet()){ os << setw(L1) << "Flavor:" << " " << ( (acceleration->algorithm_select == AccelerationContext::algorithm_autoselect) ? "auto" : ((acceleration->algorithm_select == AccelerationContext::algorithm_dense) ? "dense" : "sparse") ) << "\n"; } if (AccelerationMeta::isAccTypeGPU(acceleration->mode)){ os << setw(L1) << "GPU:" << " " << getGPUID() << '\n'; } os << std::endl; } void TasmanianSparseGrid::writeAscii(std::ostream &ofs) const{ ofs << "TASMANIAN SG " << getVersion() << '\n'; ofs << "WARNING: do not edit this manually\n"; if (isGlobal()){ ofs << "global\n"; }else if (isSequence()){ ofs << "sequence\n"; }else if (isLocalPolynomial()){ ofs << "localpolynomial\n"; }else if (isWavelet()){ ofs << "wavelet\n"; }else if (isFourier()){ ofs << "fourier\n"; }else{ ofs << "empty\n"; } if (!empty()) base->write(ofs, mode_ascii); if (domain_transform_a.size() != 0){ ofs << "custom\n"; ofs << std::scientific; ofs.precision(17); for(int j=0; jgetNumDimensions(); j++){ ofs << domain_transform_a[j] << " " << domain_transform_b[j] << '\n'; } }else{ ofs << "canonical\n"; } if (conformal_asin_power.size() != 0){ ofs << "asinconformal\n"; IO::writeVector(conformal_asin_power, ofs); }else{ ofs << "nonconformal\n"; } if (!llimits.empty()){ ofs << "limited\n"; IO::writeVector(llimits, ofs); }else{ ofs << "unlimited\n"; } if (using_dynamic_construction){ ofs << "constructing\n"; base->writeConstructionData(ofs, mode_ascii); }else{ ofs << "static\n"; } ofs << "TASMANIAN SG end" << std::endl; } void TasmanianSparseGrid::writeBinary(std::ostream &ofs) const{ const char *TSG = "TSG5"; // last char indicates version (update only if necessary, no need to sync with getVersionMajor()) ofs.write(TSG, 4 * sizeof(char)); // mark Tasmanian files // use Integers to indicate grid types, empty 'e', global 'g', sequence 's', pwpoly 'p', wavelet 'w', Fourier 'f' if (isGlobal()){ IO::writeNumbers(ofs, 'g'); }else if (isSequence()){ IO::writeNumbers(ofs, 's'); }else if (isLocalPolynomial()){ IO::writeNumbers(ofs, 'p'); }else if (isWavelet()){ IO::writeNumbers(ofs, 'w'); }else if (isFourier()){ IO::writeNumbers(ofs, 'f'); }else{ IO::writeNumbers(ofs, 'e'); } if (!empty()) base->write(ofs, mode_binary); // domain transform: custom 'y', canonical: 'n' if (domain_transform_a.size() != 0){ IO::writeNumbers(ofs, 'y'); IO::writeVector(domain_transform_a, ofs); IO::writeVector(domain_transform_b, ofs); }else{ IO::writeNumbers(ofs, 'n'); } // conformal transforms: none 'n', asin 'a' if (conformal_asin_power.size() != 0){ IO::writeNumbers(ofs, 'a'); IO::writeVector(conformal_asin_power, ofs); }else{ IO::writeNumbers(ofs, 'n'); } if (!llimits.empty()){ IO::writeNumbers(ofs, 'y'); IO::writeVector(llimits, ofs); }else{ IO::writeNumbers(ofs, 'n'); } if (using_dynamic_construction){ IO::writeNumbers(ofs, 'c'); base->writeConstructionData(ofs, mode_binary); }else{ IO::writeNumbers(ofs, 's'); } IO::writeNumbers(ofs, 'e'); // E stands for END } void TasmanianSparseGrid::readAscii(std::istream &ifs){ std::unique_ptr new_base; std::vector new_domain_transform_a, new_domain_transform_b; std::vector new_conformal_asin_power; std::vector new_llimits; bool new_using_dynamic_construction = false; std::string T; std::string message = ""; // used in case there is an exception ifs >> T; if (!(T.compare("TASMANIAN") == 0)){ throw std::runtime_error("ERROR: wrong file format, first word in not 'TASMANIAN'"); } ifs >> T; if (!(T.compare("SG") == 0)){ throw std::runtime_error("ERROR: wrong file format, second word in not 'SG'"); } getline(ifs, T); T.erase(0,1); if (!(T.compare(getVersion()) == 0)){ // grids with version prior to 3.0 are not supported size_t dec = T.find("."); if (dec == std::string::npos) throw std::runtime_error("ERROR: wrong file format, cannot read the version number"); int vmajor = stoi(T.substr(0, dec)); int vminor = stoi(T.substr(dec+1)); if (vmajor < 3) throw std::runtime_error("ERROR: file formats from versions prior to 3.0 are not supported"); if ((vmajor > getVersionMajor()) || ((vmajor == getVersionMajor()) && (vminor > getVersionMinor()))){ message += "ERROR: using future file format " + std::to_string(vmajor) + ", Tasmanian cannot time-travel."; throw std::runtime_error(message); } // else: using file format older than current but newer than 3.0, it is supposed to work } getline(ifs, T); if (!(T.compare("WARNING: do not edit this manually") == 0)){ throw std::runtime_error("ERROR: wrong file format, missing warning message"); } ifs >> T; clear(); if (T.compare("global") == 0){ new_base = readGridVersion5(acceleration.get(), ifs, IO::mode_ascii_type()); }else if (T.compare("sequence") == 0){ new_base = readGridVersion5(acceleration.get(), ifs, IO::mode_ascii_type()); }else if (T.compare("localpolynomial") == 0){ new_base = readGridVersion5(acceleration.get(), ifs, IO::mode_ascii_type()); }else if (T.compare("wavelet") == 0){ new_base = readGridVersion5(acceleration.get(), ifs, IO::mode_ascii_type()); }else if (T.compare("fourier") == 0){ new_base = readGridVersion5(acceleration.get(), ifs, IO::mode_ascii_type()); }else if (T.compare("empty") != 0){ throw std::runtime_error("ERROR: wrong file format, unknown grid type (or corrupt file)"); } getline(ifs, T); // read an empty line getline(ifs, T); bool reached_eof = false; if (T.compare("TASMANIAN SG end") == 0){ // version 3.0 did not include domain transform reached_eof = true; }else if (T.compare("custom") == 0){ // handle domain transform new_domain_transform_a.resize(new_base->getNumDimensions()); new_domain_transform_b.resize(new_base->getNumDimensions()); for(int j=0; jgetNumDimensions(); j++){ ifs >> new_domain_transform_a[j] >> new_domain_transform_b[j]; } getline(ifs, T); }else if (T.compare("canonical") != 0){ // canonical transform requires no action throw std::runtime_error("ERROR: wrong file format, domain unspecified"); } if (!reached_eof){ // handle conformal maps, added in version 5.0 getline(ifs, T); if (T.compare("asinconformal") == 0){ new_conformal_asin_power = IO::readVector(ifs, new_base->getNumDimensions()); getline(ifs, T); }else if (T.compare("TASMANIAN SG end") == 0){ // for compatibility with version 4.0/4.1 and the missing conformal maps reached_eof = true; }else if (T.compare("nonconformal") != 0){ throw std::runtime_error("ERROR: wrong file format, conformal mapping is unspecified"); } } if (!reached_eof){ // handle level limits, added in version 5.1 getline(ifs, T); if (T.compare("limited") == 0){ new_llimits = IO::readVector(ifs, new_base->getNumDimensions()); getline(ifs, T); }else if (T.compare("unlimited") == 0){ new_llimits = std::vector(); }else if (T.compare("TASMANIAN SG end") == 0){ reached_eof = true; }else{ throw std::runtime_error("ERROR: wrong file format, did not specify level limits"); } } if (!reached_eof){ // handles additional data for dynamic construction, added in version 7.0 (development 6.1) getline(ifs, T); if (T.compare("constructing") == 0){ new_using_dynamic_construction = true; new_base->readConstructionData(ifs, mode_ascii); getline(ifs, T); // clear the final std::endl after reading the block }else if (T.compare("TASMANIAN SG end") == 0){ reached_eof = true; }else if (T.compare("static") != 0){ // static construction requires no additional work throw std::runtime_error("ERROR: wrong file format, did not specify construction method"); } } if (!reached_eof){ getline(ifs, T); if (!(T.compare("TASMANIAN SG end") == 0)){ throw std::runtime_error("ERROR: wrong file format, did not end with 'TASMANIAN SG end' (possibly corrupt file)"); } } base = std::move(new_base); domain_transform_a = std::move(new_domain_transform_a); domain_transform_b = std::move(new_domain_transform_b); conformal_asin_power = std::move(new_conformal_asin_power); llimits = std::move(new_llimits); using_dynamic_construction = new_using_dynamic_construction; } void TasmanianSparseGrid::readBinary(std::istream &ifs){ std::vector new_domain_transform_a, new_domain_transform_b; std::vector new_conformal_asin_power; std::vector new_llimits; bool new_using_dynamic_construction = false; std::vector TSG(4); ifs.read(TSG.data(), 4*sizeof(char)); if ((TSG[0] != 'T') || (TSG[1] != 'S') || (TSG[2] != 'G')){ throw std::runtime_error("ERROR: wrong binary file format, first 3 bytes are not 'TSG'"); } if (TSG[3] != '5'){ throw std::runtime_error("ERROR: wrong binary file format, version number is not '5'"); } clear(); std::unique_ptr new_base = [&](char grid_type)->std::unique_ptr{ switch (grid_type){ case 'g': return readGridVersion5(acceleration.get(), ifs, IO::mode_binary_type()); case 's': return readGridVersion5(acceleration.get(), ifs, IO::mode_binary_type()); case 'p': return readGridVersion5(acceleration.get(), ifs, IO::mode_binary_type()); case 'w': return readGridVersion5(acceleration.get(), ifs, IO::mode_binary_type()); case 'f': return readGridVersion5(acceleration.get(), ifs, IO::mode_binary_type()); case 'e': return std::unique_ptr(); default: throw std::runtime_error("ERROR: wrong binary file format, unknown grid type"); }; }(IO::readNumber(ifs)); char flag = IO::readNumber(ifs); if (flag == 'y'){ new_domain_transform_a = IO::readVector(ifs, new_base->getNumDimensions()); new_domain_transform_b = IO::readVector(ifs, new_base->getNumDimensions()); }else if (flag != 'n'){ throw std::runtime_error("ERROR: wrong binary file format, wrong domain type"); } flag = IO::readNumber(ifs); // conformal domain transform? if (flag == 'a'){ new_conformal_asin_power = IO::readVector(ifs, new_base->getNumDimensions()); }else if (flag != 'n'){ throw std::runtime_error("ERROR: wrong binary file format, wrong conformal transform type"); } flag = IO::readNumber(ifs); // limits if (flag == 'y'){ new_llimits = IO::readVector(ifs, new_base->getNumDimensions()); }else if (flag != 'n'){ throw std::runtime_error("ERROR: wrong binary file format, wrong level limits"); } bool reached_eof = false; flag = IO::readNumber(ifs); // construction data if (flag == 'c'){ // handles additional data for dynamic construction, added in version 7.0 (development 6.1) new_using_dynamic_construction = true; new_base->readConstructionData(ifs, mode_binary); }else if (flag == 'e'){ reached_eof = true; }else if (flag != 's'){ throw std::runtime_error("ERROR: wrong binary file format, wrong construction method specified"); } if (!reached_eof){ if (IO::readNumber(ifs) != 'e'){ throw std::runtime_error("ERROR: wrong binary file format, did not reach correct end of Tasmanian block"); } } base = std::move(new_base); domain_transform_a = std::move(new_domain_transform_a); domain_transform_b = std::move(new_domain_transform_b); conformal_asin_power = std::move(new_conformal_asin_power); llimits = std::move(new_llimits); using_dynamic_construction = new_using_dynamic_construction; } void TasmanianSparseGrid::enableAcceleration(TypeAcceleration acc){ // if gpu acceleration has been disabled, then reset the domain and cache // note that this method cannot possibly change the gpu ID and switching // between variations of GPU accelerations on the same device will keep the same cache AccelerationContext::ChangeType change = acceleration->testEnable(acc, acceleration->device); if (not empty()) base->updateAccelerationData(change); if (change == AccelerationContext::change_gpu_device) acc_domain.reset(); acceleration->enable(acc, acceleration->device); } void TasmanianSparseGrid::enableAcceleration(TypeAcceleration acc, int new_gpu_id){ AccelerationContext::ChangeType change = acceleration->testEnable(acc, new_gpu_id); if (not empty()) base->updateAccelerationData(change); if (change == AccelerationContext::change_gpu_device) acc_domain.reset(); acceleration->enable(acc, new_gpu_id); } void TasmanianSparseGrid::favorSparseAcceleration(bool favor){ AccelerationContext::ChangeType change = acceleration->favorSparse(favor); if (not empty()) base->updateAccelerationData(change); } #ifdef Tasmanian_ENABLE_CUDA void TasmanianSparseGrid::setCuBlasHandle(void *handle){ if (acceleration->on_gpu()){ acceleration->engine->setCuBlasHandle(handle); }else{ throw std::runtime_error("setCuBlasHandle() called with non-GPU acceleration mode."); } } void TasmanianSparseGrid::setCuSparseHandle(void *handle){ if (acceleration->on_gpu()){ acceleration->engine->setCuSparseHandle(handle); }else{ throw std::runtime_error("setCuSparseHandle() called with non-GPU acceleration mode."); } } void TasmanianSparseGrid::setCuSolverHandle(void *handle){ if (acceleration->on_gpu()){ acceleration->engine->setCuSolverDnHandle(handle); }else{ throw std::runtime_error("setCuSolverHandle() called with non-GPU acceleration mode."); } } #else void TasmanianSparseGrid::setCuBlasHandle(void*){ throw std::runtime_error("setCuBlasHandle() requires Tasmanian to be build with the CUDA backend."); } void TasmanianSparseGrid::setCuSparseHandle(void*){ throw std::runtime_error("setCuSparseHandle() requires Tasmanian to be build with the CUDA backend."); } void TasmanianSparseGrid::setCuSolverHandle(void*){ throw std::runtime_error("setCuSolverHandle() requires Tasmanian to be build with the CUDA backend."); } #endif #ifdef Tasmanian_ENABLE_HIP void TasmanianSparseGrid::setRocBlasHandle(void *handle){ if (acceleration->on_gpu()){ acceleration->engine->setRocBlasHandle(handle); }else{ throw std::runtime_error("setRocBlasHandle() called with non-GPU acceleration mode."); } } void TasmanianSparseGrid::setRocSparseHandle(void *handle){ if (acceleration->on_gpu()){ acceleration->engine->setRocSparseHandle(handle); }else{ throw std::runtime_error("setRocSparseHandle() called with non-GPU acceleration mode."); } } #else void TasmanianSparseGrid::setRocBlasHandle(void*){ throw std::runtime_error("setRocBlasHandle() requires Tasmanian to be build with the HIP/ROCm backend."); } void TasmanianSparseGrid::setRocSparseHandle(void*){ throw std::runtime_error("setRocSparseHandle() requires Tasmanian to be build with the HIP/ROCm backend."); } #endif #ifdef Tasmanian_ENABLE_DPCPP void TasmanianSparseGrid::setSycleQueue(void *queue){ if (acceleration->on_gpu()){ acceleration->engine->setSyclQueue(queue); }else{ throw std::runtime_error("setSyclQueue() called with non-GPU acceleration mode."); } } #else void TasmanianSparseGrid::setSycleQueue(void*){ throw std::runtime_error("setSyclQueue() requires Tasmanian to be build with the DPC++/SYCL backend."); } #endif bool TasmanianSparseGrid::isAccelerationAvailable(TypeAcceleration acc){ #ifdef Tasmanian_ENABLE_GPU if (acc == accel_gpu_default) return true; #endif return (acc == AccelerationMeta::getAvailableFallback(acc)); } void TasmanianSparseGrid::setGPUID(int new_gpu_id){ if (new_gpu_id != acceleration->device){ AccelerationContext::ChangeType change = acceleration->testEnable(acceleration->mode, new_gpu_id); if (not empty()) base->updateAccelerationData(change); #ifdef Tasmanian_ENABLE_GPU if (change == AccelerationContext::change_gpu_device) acc_domain.reset(); #endif acceleration->enable(acceleration->mode, new_gpu_id); } } int TasmanianSparseGrid::getGPUMemory(int gpu){ if ((gpu < 0) || (gpu >= AccelerationMeta::getNumGpuDevices())) return 0; return (int) (AccelerationMeta::getTotalGPUMemory(gpu) / 1048576); } std::string TasmanianSparseGrid::getGPUName(int gpu){ return AccelerationMeta::getGpuDeviceName(gpu); } } #endif TASMANIAN-8.1/SparseGrids/TasmanianSparseGrid.h000066400000000000000000000267721470551176200212210ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_H #define __TASMANIAN_SPARSE_GRID_H // ------------ C Interface for TasmanianSparseGrid -------------- // // NOTE: you need to explicitly call the constructor and destructor // in all cases, void *grid is a pointer to a C++ class void* tsgConstructTasmanianSparseGrid(); void tsgDestructTasmanianSparseGrid(void *grid); void tsgCopyGrid(void *destination, void *source); void tsgCopySubGrid(void *destination, void *source, int outputs_begin, int outputs_end); const char* tsgGetVersion(); const char* tsgGetLicense(); int tsgGetVersionMajor(); int tsgGetVersionMinor(); int tsgIsOpenMPEnabled(); int tsgIsCudaEnabled(); int tsgIsHipEnabled(); int tsgIsDpcppEnabled(); void tsgWrite(void *grid, const char* filename); void tsgWriteBinary(void *grid, const char* filename); int tsgRead(void *grid, const char* filename); void tsgMakeGlobalGrid(void *grid, int dimensions, int outputs, int depth, const char * sType, const char *sRule, const int *anisotropic_weights, double alpha, double beta, const char* custom_filename, const int *limit_levels); void tsgMakeSequenceGrid(void *grid, int dimensions, int outputs, int depth, const char *sType, const char *sRule, const int *anisotropic_weights, const int *limit_levels); void tsgMakeLocalPolynomialGrid(void *grid, int dimensions, int outputs, int depth, int order, const char *sRule, const int *limit_levels); void tsgMakeWaveletGrid(void *grid, int dimensions, int outputs, int depth, int order, const int *limit_levels); void tsgMakeFourierGrid(void *grid, int dimensions, int outputs, int depth, const char *sType, const int *anisotropic_weights, const int *limit_levels); void tsgMakeGridFromCustomTabulated(void *grid, int dimension, int outputs, int depth, const char *sType, void *custom_tabulated, const int *anisotropic_weights, const int *limit_levels) ; void tsgUpdateGlobalGrid(void *grid, int depth, const char * sType, const int *anisotropic_weights, const int *limit_levels); void tsgUpdateSequenceGrid(void *grid, int depth, const char * sType, const int *anisotropic_weights, const int *limit_levels); void tsgUpdateFourierGrid(void *grid, int depth, const char * sType, const int *anisotropic_weights, const int *limit_levels); double tsgGetAlpha(void *grid); double tsgGetBeta(void *grid); int tsgGetOrder(void *grid); int tsgGetNumDimensions(void *grid); int tsgGetNumOutputs(void *grid); char* tsgGetRule(void *grid); void tsgCopyRuleChars(void *grid, int buffer_size, char *name, int *num_actual); const char* tsgGetCustomRuleDescription(void *grid); int tsgGetNumLoaded(void *grid); int tsgGetNumNeeded(void *grid); int tsgGetNumPoints(void *grid); void tsgGetLoadedPointsStatic(void *grid, double *x); double* tsgGetLoadedPoints(void *grid); void tsgGetNeededPointsStatic(void *grid, double *x); double* tsgGetNeededPoints(void *grid); void tsgGetPointsStatic(void *grid, double *x); double* tsgGetPoints(void *grid); void tsgGetQuadratureWeightsStatic(void *grid, double *weights); double* tsgGetQuadratureWeights(void *grid); void tsgGetInterpolationWeightsStatic(void *grid, const double *x, double *weights); double* tsgGetInterpolationWeights(void *grid, const double *x); void tsgLoadNeededPoints(void *grid, const double *vals); void tsgLoadNeededValues(void *grid, const double *vals); const double* tsgGetLoadedValues(void *grid); void tsgGetLoadedValuesStatic(void *grid, double *values); void tsgEvaluate(void *grid, const double *x, double *y); void tsgEvaluateFast(void *grid, const double *x, double *y); void tsgIntegrate(void *grid, double *q); void tsgDifferentiate(void *grid, const double *x, double *y); void tsgEvaluateBatch(void *grid, const double *x, int num_x, double *y); void tsgBatchGetInterpolationWeightsStatic(void *grid, const double *x, int num_x, double *weights); double* tsgBatchGetInterpolationWeights(void *grid, const double *x, int num_x); int tsgIsGlobal(void *grid); int tsgIsSequence(void *grid); int tsgIsLocalPolynomial(void *grid); int tsgIsWavelet(void *grid); int tsgIsFourier(void *grid); void tsgSetDomainTransform(void *grid, const double a[], const double b[]); int tsgIsSetDomainTransfrom(void *grid); void tsgClearDomainTransform(void *grid); void tsgGetDomainTransform(void *grid, double a[], double b[]); void tsgSetConformalTransformASIN(void *grid, const int truncation[]); int tsgIsSetConformalTransformASIN(void *grid); void tsgClearConformalTransform(void *grid); void tsgGetConformalTransformASIN(void *grid, int truncation[]); void tsgClearLevelLimits(void *grid); void tsgGetLevelLimits(void *grid, int *limits); void tsgSetAnisotropicRefinement(void *grid, const char * sType, int min_growth, int output, const int *level_limits); int* tsgEstimateAnisotropicCoefficients(void *grid, const char * sType, int output, int *num_coefficients); void tsgEstimateAnisotropicCoefficientsStatic(void *grid, const char * sType, int output, int *coefficients); void tsgSetGlobalSurplusRefinement(void *grid, double tolerance, int output, const int *level_limits); void tsgSetLocalSurplusRefinement(void *grid, double tolerance, const char * sRefinementType, int output, const int *level_limits, const double *scale_correction); void tsgClearRefinement(void *grid); void tsgMergeRefinement(void *grid); void tsgBeginConstruction(void *grid); int tsgIsUsingConstruction(void *grid); void* tsgGetCandidateConstructionPointsVoidPntr(void *grid, const char *sType, int output, const int *anisotropic_weights, const int *limit_levels); void* tsgGetCandidateConstructionPointsSurplusVoidPntr(void *grid, double tolerance, const char *sRefType, int output, const int *limit_levels, const double *scale_correction); void tsgGetCandidateConstructionPoints(void *grid, const char *sType, int output, const int *anisotropic_weights, const int *limit_levels, int *num_points, double **x); void tsgGetCandidateConstructionSurplusPoints(void *grid, double tolerance, const char *sRefType, int output, const int *limit_levels, const double *scale_correction, int *num_points, double **x); int tsgGetCandidateConstructionPointsPythonGetNP(void *grid, const void *vecx); void tsgGetCandidateConstructionPointsPythonStatic(const void *vecx, double *x); void tsgGetCandidateConstructionPointsPythonDeleteVect(void *vecx); void tsgLoadConstructedPoint(void *grid, const double *x, int numx, const double *y); void tsgFinishConstruction(void *grid); void tsgRemovePointsByHierarchicalCoefficient(void *grid, double tolerance, int output, const double *scale_correction); void tsgRemovePointsByHierarchicalCoefficientHardCutoff(void *grid, int num_new, int output, const double *scale_correction); void tsgEvaluateHierarchicalFunctions(void *grid, const double *x, int num_x, double *y); void tsgEvaluateSparseHierarchicalFunctions(void *grid, const double x[], int num_x, int **pntr, int **indx, double **vals); int tsgEvaluateSparseHierarchicalFunctionsGetNZ(void *grid, const double x[], int num_x); void tsgEvaluateSparseHierarchicalFunctionsStatic(void *grid, const double x[], int num_x, int *pntr, int *indx, double *vals); void tsgGetHierarchicalSupportStatic(void *grid, double support[]); const double* tsgGetHierarchicalCoefficients(void *grid); void tsgGetHierarchicalCoefficientsStatic(void *grid, double *coeff); void tsgSetHierarchicalCoefficients(void *grid, const double *c); double* tsgIntegrateHierarchicalFunctions(void *grid); void tsgIntegrateHierarchicalFunctionsStatic(void *grid, double *integrals); // to be called from Python only, must later call delete[] on the pointer int* tsgPythonGetGlobalPolynomialSpace(void *grid, int interpolation, int *num_indexes); // to be used in C, creates a C pointer (requires internal copy of data) void tsgGetGlobalPolynomialSpace(void *grid, int interpolation, int *num_indexes, int **indexes); void tsgPrintStats(void *grid); void tsgEnableAcceleration(void *grid, const char *accel); void tsgEnableAccelerationGPU(void *grid, const char *accel, int gpu); //int tsgGetAccelerationTypeInt(void *grid){ return AccelerationMeta::getIOAccelerationInt(((TasmanianSparseGrid*) grid)->getAccelerationType()); } // int to acceleration type const char* tsgGetAccelerationType(void *grid); void tsgSetGPUID(void *grid, int gpuID); int tsgGetGPUID(void *grid); int tsgGetNumGPUs(); int tsgGetGPUMemory(int gpu); int tsgIsAccelerationAvailable(const char *accel); void tsgGetGPUName(int gpu, int num_buffer, char *buffer, int *num_actual); void tsgDeleteInts(int *p); void* tsgConstructCustomTabulated(); void tsgDestructCustomTabulated(void* ct); void tsgWriteCustomTabulated(void *ct, const char* filename); int tsgReadCustomTabulated(void *ct, const char* filename); int tsgGetNumLevelsCustomTabulated(void* ct); int tsgGetNumPointsCustomTabulated(void* ct, const int level); int tsgGetIExactCustomTabulated(void* ct, const int level); int tsgGetQExactCustomTabulated(void* ct, const int level); const char* tsgGetDescriptionCustomTabulated(void* ct) ; void tsgGetWeightsNodesStaticCustomTabulated(void* ct, int level, double* w, double* x) ; // Note: cnodes and cweights are passed as 1D arrays, but represent a list of vectors. void* tsgMakeCustomTabulatedFromData(const int cnum_levels, const int* cnum_nodes, const int* cprecision, const double* cnodes, const double* cweights, char* cdescription) ; void* tsgGetSubrules(void* ct, const int start_index, const int stride, char* description) ; #endif TASMANIAN-8.1/SparseGrids/TasmanianSparseGrid.hpp000066400000000000000000003661161470551176200215600ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ /*! * \internal * \file TasmanianSparseGrid.hpp * \brief Main header for the Sparse Grid module. * \author Miroslav Stoyanov * \ingroup TasmanianSG * * The header needed to access the Tasmanian sparse grids module, * the TasGrid::TasmanianSparseGrids class is defined here. * \endinternal */ #ifndef __TASMANIAN_SPARSE_GRID_HPP #define __TASMANIAN_SPARSE_GRID_HPP #include "tsgGridGlobal.hpp" #include "tsgGridLocalPolynomial.hpp" #include "tsgGridWavelet.hpp" #include "tsgGridFourier.hpp" /*! * \defgroup TasmanianSG Sparse Grids * * \par Sparse Grids * A family of algorithms for multidimensional integration and interpolation * where the operator is constructed as a linear combination of tensors * with different number of points in each direction. * The combination of tensors is chosen to include a specific function space * that is optimal for approximation of the target model. * For more details of the sparse grid construction, refer to the * .pdf manual available at [http://tasmanian.ornl.gov/](http://tasmanian.ornl.gov/) */ /*! * \ingroup TasmanianSG * \brief Encapsulates the Tasmanian Sparse Grid module. */ namespace TasGrid{ /*! * \ingroup TasmanianSG * \addtogroup TasmanianSGClass Sparse Grid Class * * The sparse grid capabilities of Tasmanian are encapsulated in a single master class * TasGrid::TasmanianSparseGrid. */ /*! * \ingroup TasmanianSGClass * \brief The master-class that represents an instance of a Tasmanian sparse grid. * * \par class TasmanianSparseGrid * An object of this class represents a sparse grid, all aspects of the grid * can be accessed through member methods. * Each object operates independently to the extend allowed by third-party * libraries, e.g., making concurrent calls to OpenBLAS will result in a race * condition unless OpenBLAS is compiled with a special flag. * The available member methods are split into groups that deal with * different aspects of the grid. * The object itself wraps around one of five different types of grids, * Global, Sequence, Local Polynomial, Wavelet, and Fourier, * each using different back-end data structures. * The class itself handles the domain transformations, * e.g., the translation between the canonical [-1, 1] and a user provided [a, b], * as well as mechanisms to select acceleration back-end, common meta I/O, * and error checking. * * \par Error Handling * \b TasmanianSparseGrid throws \b std::invalid_argument and \b std::runtime_error * exceptions with simple human-readable messages. * The \b std::invalid_argument exception indicates method call arguments of * insufficient or incompatible data, e.g., vectors have insufficient size * or negative number was given in place of a positive one. * The \b std::runtime_error indicates problems with missing files, incorrect * file format, or out-of-order function calls, e.g., adaptive refinement * strategies require model values in order to infer the optimal structure of * the grid, therefore calling a refinement method before model values are * provided will result in a \b std::runtime_error. * Similarly, \b std::runtime_error will be thrown if a method is called * with the wrong grid type, e.g., global anisotropic coefficients cannot be * computed for local polynomial grids. * * If CUDA acceleration is used, CUDA error may be encountered, e.g., * incorrect driver initialization, out-of-memory, etc. * Tasmanian will translate CUDA error codes and messages into * \b std::runtime_error exceptions and such exceptions can be raised * by any method that uses acceleration. * * \par Constructors and Copy/Move assignment * TasGrid::TasmanianSparseGrid includes move and copy constructors * and assignment operator= overloads. * There is also a default constructor that creates an empty grid. * Note that move will preserve the enabled acceleration mode and the internal * cache data-structures, while copy will reset the acceleration to the default. * - TasmanianSparseGrid() * - copyGrid() * * \par Make Grid Methods * Each of the five grid types comes with a separate make command. * The first three parameters are always the number of inputs (dimensions), * the number of outputs, and the initial depth or level of the grid. * The remaining parameters are specific to the type of grid. * - makeGlobalGrid() * - makeSequenceGrid() * - makeLocalPolynomialGrid() * - makeWaveletGrid() * - makeFourierGrid() * - see also the factory methods, e.g., TasGrid::makeGlobalGrid() * * \par Domain Transformations * In most cases, sparse grids are constructed on a canonical domain [-1, 1]. * The exceptions are the Fourier grids with domain [0, 1], and the * Gauss-Hermite and Gauss-Laguerre rules with unbounded domain, see * TasGrid::rule_gausshermite and TasGrid::rule_gausslaguerre for details. * Tasmanian can automatically apply a linear domain transformations shifting * the canonical interval to an arbitrary [a, b] or a non-linear (conformal) * transformation that may accelerate convergence for some models. * Each dimension of the grid can have a different linear and/or non-linear * transform. * - setDomainTransform(), getDomainTransform() * - isSetDomainTransfrom(), clearDomainTransform() * - setConformalTransformASIN(), getConformalTransformASIN() * - isSetConformalTransformASIN(), clearConformalTransform() * * \par Stream and File I/O * Sparse grid objects can be written to and from files and \b std::ostream objects. * Tasmanian supports both binary and ASCII formats; the binary format * has lower overhead in both file size and operations required to read/write, * the ASCII format is portable without considerations of endians and * for small grids the files are human-readable which helps debugging. * - read(), TasGrid::readGrid() * - write() * * \par Get Points and Weights * The points on the grid are labeled as "loaded" or "needed" based on * whether the associated model values are already provided by the user. * The grid points are also associated with quadrature, interpolation, * and differentiation weights, where the computed weights correspond * to the loaded points unless all points are labeled as needed. If the * grid is set to work with zero model outputs, then the distinction is * meaningless and the points will be accessed through the generic * getPoints() methods. * - getNumLoaded(), getNumNeeded(), getNumPoints() * - getLoadedPoints(), getNeededPoints(), getPoints() * - getLoadedValues() * - getQuadratureWeights() * - getInterpolationWeights() * - getDifferentiationWeights() * * \par Load Model Values or Hierarchical Coefficients * In order to construct an interpolant, Tasmanian needed to compute the * coefficients of the basis functions. The user can directly provide the * coefficients, e.g., computed externally with a regression method using * an unstructured set of samples, or the user can provide the model values * at the needed points and let Tasmanian do the computations. * - TasGrid::loadNeededValues(), TasGrid::loadNeededPoints() * - loadNeededValues(), getLoadedValues(), loadNeededPoints() * - setHierarchicalCoefficients() * * \par Update and Adaptive Refinement * The most efficient approximation schemes adapt the grid (and the associated * basis functions) to the target model. Tasmanian provides several adaptive * procedures tailored to different types of grids. * The refinement requires two-way communication between the model and * Tasmanian, i.e., Tasmanian provides an initial set of points, the model * provides the values, then Tasmanian provides an updated set of points, and so on. * This can be done either in batches of point or in dynamic construction setup * where values can be given one at a time in an arbitrary order (see next paragraph). * See also the papers referenced in TasGrid::TypeDepth and TasGrid::TypeRefinement. * - updateGrid() * - setAnisotropicRefinement(), setSurplusRefinement() * - getAnisotropicRefinement(), getSurplusRefinement() * - clearRefinement() * - getLevelLimits(), clearLevelLimits() * - removePointsByHierarchicalCoefficient() * * \par Dynamic Construction * The standard refinement procedure works in batches, where all model values * for the batch have to be computed externally and loaded together in the * correct order. The dynamic construction alleviates those restrictions, * but comes at an increase cost since Tasmanian has to do more work and * store extra data. The dynamic construction (and the internal data-structures) * are initiated with the beginConstruction() command and batch refinement * cannot be used until the procedure is concluded. See also TasGrid::constructSurrogate() * that can take a user defined model and fully automate the construction process. * - TasGrid::constructSurrogate() * - beginConstruction(), finishConstruction() * - getCandidateConstructionPoints() * - loadConstructedPoints() * * \par Using Unstructured Data * The standard sparse grid methods assume that model data is available at the very * specific grid points that are chosen according to optimal estimates. * However, in some cases, the model inputs cannot be controlled precisely * and only randomly samples model data is available. * Sparse grids can still produce accurate surrogates using such unstructured * data by effectively removing the points and working only with the underlying * basis (the basis is still optimal for the corresponding class of functions). * The hierarchical basis method allow direct access to the values of * the basis functions and the associated coefficients. * - evaluateHierarchicalFunctions(), evaluateSparseHierarchicalFunctions() * - evaluateHierarchicalFunctionsGPU(), evaluateSparseHierarchicalFunctionsGPU() * - setHierarchicalCoefficients(), getHierarchicalCoefficients() * - integrateHierarchicalFunctions() * - getHierarchicalSupport() * * \par Evaluate Methods * The evaluate methods compute the sparse grid approximation to the model for * arbitrary point within the domain, i.e., for points that don't necessarily * align with the original grid. * The batch and fast evaluate method can leverage accelerated linear algebra * libraries such as BLAS, cuBLAS and MAGAMA. * See the documentation for TasGrid::TypeAcceleration for details. * - evaluate() * - evaluateBatch(), evaluateBatchGPU(), evaluateFast() * - integrate() * * \par Acceleration Back-end Selection * Allows specifying the acceleration used for evaluation methods and (in some * cases) for computing the basis coefficients during loadNeededValues(). * For example, methods are provided to check the number of available CUDA * devices and to select an active device on a multi-GPU system. * - enableAcceleration(), getAccelerationType(), favorSparseAcceleration() * - setGPUID(), getGPUID(), getNumGPUs() * - isAccelerationAvailable(), getGPUName(), getGPUMemory() * * \par Set User Provided Handles for Accelerated Linear Algebra * Acceleration frameworks such as CUDA ROCm and oneAPI use handles and queues * that are either opaque pointers to internal data-structures (CUDA and ROCm) * or queues that must be used for all types of acceleration and data operations. * A Tasmanian object will allocate internal handles as needed, but the user can * specify the handles manually. The handles must be set after a GPU capable * acceleration has been enabled via enableAcceleration(), Tasmanian takes * a non-owning reference and the user is responsible for deleting the handle * \b after the Tasmanian object has been destroyed or a non-GPU acceleration * is selected, i.e., accel_none or accel_cpu_blas. The handles are accepted * as void-pointers (the type is stripped) to keep consistent API since only * one GPU framework can be enabled in a single Tasmanian build and the headers * for the other frameworks will not be present. * - \b (CUDA) setCuBlasHandle(), setCuSparseHandle(), setCuSolverHandle() * - \b (ROCm) setRocBlasHandle(), setRocSparseHandle() * - \b (oneAPI) setSycleQueue() * * \par Get Grid Meta-data * Various method that read the number of points, grid type, specifics about * the rule and domain transformations and others. * Some of the output is in human-readable format for debugging and sanity check. * - getNumDimensions(), getNumOutputs(), getRule() * - getCustomRuleDescription() * - getAlpha(), getBeta(), getOrder() * - isGlobal(), isSequence(), isLocalPolynomial(), isFourier(), isWavelet() * - isEmpty(), empty() * - printStats() * * \par Get Library Meta-data * Runtime API is provided for the library version and various compile * time options. * Those methods are \b static and are included in the class API solely for * consistency reasons. * - getVersion(), getVersionMajor(), getVersionMinor(), getLicense() * - getGitCommitHash(), getCmakeCxxFlags(), isOpenMPEnabled() */ class TasmanianSparseGrid{ public: //! \brief Default constructor, creates and empty grid. TasmanianSparseGrid(); //! \brief Copy constructor, note that the selected acceleration mode is not copied, acceleration is reset to the default. TasmanianSparseGrid(const TasmanianSparseGrid &source); //! \brief Move constructor, the selected acceleration mode is also carried over. TasmanianSparseGrid(TasmanianSparseGrid &&source) = default; //! \brief Destructor, releases all resources. ~TasmanianSparseGrid() = default; //! \brief Copy assignment, note that the selected acceleration mode is not copied, acceleration is reset to the default. TasmanianSparseGrid& operator=(TasmanianSparseGrid const &source); //! \brief Move assignment, the selected acceleration mode is also carried over. TasmanianSparseGrid& operator=(TasmanianSparseGrid &&source) = default; //! \brief Return a hard-coded character string with the version in format "Major.Minor". static const char* getVersion(); // human readable //! \brief Return the library major version. static int getVersionMajor(); //! \brief Return the library minor version. static int getVersionMinor(); //! \brief Return a hard-coded character string with a brief statement of the license. static const char* getLicense(); // human readable //! \brief Return the git hash string, will use a placeholder if the git command was not found on compile time or if building from an official release. static const char* getGitCommitHash(); //! \brief Return the CMAKE_BUILD_TYPE and CMAKE_CXX_FLAGS used in the configuration. static const char* getCmakeCxxFlags(); //! \brief Returns \b true if compiled with OpenMP support, e.g., Tasmanian_ENABLE_OPENMP=ON. static bool isOpenMPEnabled(); //! \brief Returns \b true if compiled with CUDA support, e.g., Tasmanian_ENABLE_CUDA=ON. static bool isCudaEnabled(); //! \brief Returns \b true if compiled with HIP support, e.g., Tasmanian_ENABLE_HIP=ON. static bool isHipEnabled(); //! \brief Returns \b true if compiled with DPC++ support, e.g., Tasmanian_ENABLE_DPCPP=ON. static bool isDpcppEnabled(); //! \brief Write the grid to the given \b filename using either \b binary or ASCII format. void write(const char *filename, bool binary = mode_binary) const; //! \brief Read the grid from the given \b filename, automatically detect the format. void read(const char *filename); // auto-check if format is binary or ascii //! \brief Write the grid to the given stream \b ofs using either \b binary or ASCII format. void write(std::ostream &ofs, bool binary = mode_binary) const; //! \brief Read the grid from the given stream \b ifs using either \b binary or ASCII format. void read(std::istream &ifs, bool binary = mode_binary); //! \brief Overload that works directly with std::string void write(std::string const& fname, bool binary = mode_binary) const{ write(fname.c_str(), binary); } //! \brief Overload that works directly with std::string void read(std::string const& fname){ read(fname.c_str()); } /*! * \brief Make a Global Grid using Lagrange polynomials with support over the entire domain. * * Construct a sparse grid with the given set of parameters. * \param dimensions is a positive integer specifying the dimension or number of model inputs of the grid. * There is no hard restriction on how big the dimension can be; however, for large dimensions, * the number of points of the sparse grid grows fast and hence the grid may require a prohibitive amount of memory. * \param outputs is a non-negative integer specifying the number of outputs for the model. * If outputs is zero, then the grid can only generate quadrature and interpolation weights. * There is no hard restriction on how many outputs can be handled; however, Tasmanian requires at least * outputs times number of points in storage and the computational complexity of evaluate and I/O methods * increases linearly with the number of outputs. * \param depth is a non-negative integer that controls the density of grid points. * This is commonly referred to the "level" of the grid and corresponds to the L parameter * in the formulas for TasGrid::TypeDepth. There is no hard restriction on how big depth can be; * however, the number of points have a strong influence on performance and memory requirements. * \param type indicates the tensor selection strategy, see TasGrid::TypeDepth. * \param rule is one of the global rules, see TasGrid::TypeOneDRule. * \param anisotropic_weights indicates the relative "importance" of the inputs. * If an empty vector is provided, the isotropic selection is used, i.e., assuming all inputs * are equally important. * If non-empty vector is given, then the size must match the number of required weights * based on the selection \b type, i.e., the \b curved types use 2 x \b dimensions number of * weights while the non-curved types use only \b dimensions. * Integer values are used, but only the relative scale affects the selection, * e.g., {2, 1}, {4, 2}, {20, 10} and {200, 100} are equivalent. * The first \b dimensions entries correspond to the \f$ \xi_1, \xi_2, \cdots, \xi_d \f$ weights * and the second set corrections to the \f$ \eta_1, \eta_2, \cdots, \eta_d \f$ weights * in the formulas in TasGrid::TypeDepth. * \param alpha specifies the \f$ \alpha \f$ parameter for the integration weight \f$ \rho(x) \f$, * ignored when \b rule is doesn't have such parameter. See TasGrid::TypeOneDRule. * \param beta specifies the \f$ \beta \f$ parameter for the integration weight \f$ \rho(x) \f$, * ignored when \b rule is doesn't have such parameter. See TasGrid::TypeOneDRule. * \param custom_filename specifies the file containing the custom rule description, * used only when \b rule is TasGrid::rule_customtabulated. * \param level_limits is either empty or has size \b dimensions indicating the restriction * of the levels for each direction which in turn restricts the number of points. * For example, limit 1 when using TasGrid::rule_clenshawcurtis will restricts the grid to the * mid-point and end-points of the domain. Each dimension can have a different restriction * and negative numbers indicate no restriction for that direction. * * \throws std::invalid_argument with human readable messages when integers are out of range, * the \b rule is not a global rule, or the vectors have incorrect size. * \throws std::runtime_error if the \b custom_filename if missing, or it cannot be opened, * or the format is incorrect. */ void makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, std::vector const &anisotropic_weights, double alpha = 0.0, double beta = 0.0, const char* custom_filename = nullptr, std::vector const &level_limits = std::vector()); /*! * \brief Overload using raw-arrays. * * The inputs are the same as \b makeGlobalGrid() except the vectors are replaced by arrays. * Passing \b nullptr for an array is equivalent to passing an empty vector. * Throws the same exceptions, but it does not check if the arrays have the correct size. */ void makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, const int *anisotropic_weights = nullptr, double alpha = 0.0, double beta = 0.0, const char* custom_filename = nullptr, const int *level_limits = nullptr); /*! * \brief Overload make a Global Grid using the provided custom rule. * * Compared to makeGlobalGrid(), this uses the provided CustomTabulated rule with rule_customtabulated. */ void makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, CustomTabulated &&crule, std::vector const &anisotropic_weights, std::vector const &level_limits = std::vector()); /*! * \brief Overload using raw-arrays. * * Same as the other CustomTabulated overload but uses raw-arrays. */ void makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, CustomTabulated &&crule, const int *anisotropic_weights = nullptr, const int *level_limits = nullptr); /*! * \brief Make Sequence Grid using Newton polynomials with support over the entire domain. * * Mathematically the Sequence and Global grids do not differ in properties; * however, the implementation of the Sequence grids uses optimized internal data structures * which leads to massive increase in speed when calling evaluate methods * at the expense of doubled memory size and increased cost of \b loadNeededValues(). * The inputs are identical to \b makeGlobalGrid() with the restriction that \b rule * must be one of: * \code * rule_rleja rule_leja rule_minlebesgue * rule_rlejashifted rule_maxlebesgue rule_mindelta * \endcode * * \throws std::invalid_argument with human readable messages when integers are out of range, * the \b rule is not a sequence rule, or the vectors have incorrect size. */ void makeSequenceGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, std::vector const &anisotropic_weights, std::vector const &level_limits = std::vector()); /*! * \brief Overload using raw-arrays. * * The inputs are the same as \b makeSequenceGrid() except the vectors are replaced by arrays. * Passing \b nullptr for an array is equivalent to passing an empty vector. * Throws the same exceptions, but it does not check if the arrays have the correct size. */ void makeSequenceGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, const int *anisotropic_weights = nullptr, const int *level_limits = nullptr); /*! * \brief Make Local Polynomial Grid using piece-wise polynomials with decreasing (compact) support. * * Creates a grid based on one of the local hierarchical piece-wise polynomial rules. * Local grids can be used for integration, but in many cases the quadrature weights will be zero for some points. * \param dimensions is a positive integer specifying the dimension or number of model inputs of the grid. * See also makeGlobalGrid(). * \param outputs is a non-negative integer specifying the number of outputs for the model. * Unlike makeGlobalGrid() the storage requirement is at least twice the number of points times the number of outputs. * \param depth is a non-negative integer that controls the density of grid points, i.e., the "level". * The initial construction of the local grids uses tensor selection equivalent to TasGrid::type_level * and depth is the \b L parameter in the formula. * \param order is an integer no smaller than -1 indicating the largest polynomial order of the basis functions, * i.e., 1 indicates the use of constant and linear functions only, while 2 would allow quadratics * (if enough points are present). Using -1 indicates using the largest possible order for each point. * See the papers referenced in the TasGrid::TypeRefinement description. * \param rule is one of the local polynomial rules, e.g., * \code * rule_localp rule_semilocalp rule_localp0 rule_localpb * \endcode * Note that using order \b 0 with any rule will automatically switch to a special piece-wise constant hierarchy. * \param level_limits is identical to that for makeGlobalGrid(). * * \throws std::invalid_argument with human readable messages when integers are out of range, * the \b rule is not a local polynomial rule, or the vector has incorrect size. */ void makeLocalPolynomialGrid(int dimensions, int outputs, int depth, int order, TypeOneDRule rule, std::vector const &level_limits); /*! * \brief Overload using raw-arrays. * * The inputs are the same as \b makeLocalPolynomialGrid() except the vector is replaced by an array. * Passing \b nullptr for an array is equivalent to passing an empty vector. * Throws the same exceptions, but this does not check if the array has the correct size. */ void makeLocalPolynomialGrid(int dimensions, int outputs, int depth, int order = 1, TypeOneDRule rule = rule_localp, const int *level_limits = nullptr); /*! * \brief Make a Wavelet grid using local hierarchical wavelet basis. * * Wavelets are specialized functions that form a Riesz basis and can offer better convergence in an adaptive refinement process. * See the pdf manual for more details. * \param dimensions is a positive integer specifying the dimension or number of model inputs of the grid. * See also makeGlobalGrid(). * \param outputs is a non-negative integer specifying the number of outputs for the model. * Unlike makeGlobalGrid() the storage requirement is at least twice the number of points times the number of outputs. * \param depth is a non-negative integer that controls the density of grid points, i.e., the "level". * The initial construction of the local grids uses tensor selection equivalent to TasGrid::type_level * and depth is the \b L parameter in the formula, but unlike the local polynomial hierarchies * the zero-th level has 3 or 5 points and hence the grid density is overall higher. * \param order is the wavelet approximation order, implemented orders are only 1 and 3 (wavelet order cannot be an even number). * \param level_limits is identical to that for makeGlobalGrid(). * * \throws std::invalid_argument with human readable messages when integers are out of range, or the vector has incorrect size. */ void makeWaveletGrid(int dimensions, int outputs, int depth, int order, std::vector const &level_limits); /*! * \brief Overload using raw-arrays. * * The inputs are the same as \b makeWaveletGrid() except the vector is replaced by an array. * Passing \b nullptr for an array is equivalent to passing an empty vector. * Throws the same exceptions, but this does not check if the array has the correct size. */ void makeWaveletGrid(int dimensions, int outputs, int depth, int order = 1, const int *level_limits = nullptr); /*! * \brief Make a Fourier grid using trigonometric basis with support over the entire domain. * * The trigonometric basis guarantees that the interpolant is periodic (in all derivatives) across the domain boundary. * This is the only grid that defaults to a canonical interval [0, 1] (as opposed to [-1, 1]). * The parameters and error messages are identical to those used in makeGlobalGrid(), * but this always uses TasGrid::rule_fourier and the polynomial order in the selection * is replaced by the frequency of the trigonometric basis. */ void makeFourierGrid(int dimensions, int outputs, int depth, TypeDepth type, std::vector const &anisotropic_weights, std::vector const &level_limits = std::vector()); /*! * \brief Overload using raw-arrays. * * The inputs are the same as \b makeFourierGrid() except the vectors are replaced by arrays. * Passing \b nullptr for an array is equivalent to passing an empty vector. * Throws the same exceptions, but it does not check if the arrays have the correct size. */ void makeFourierGrid(int dimensions, int outputs, int depth, TypeDepth type, const int* anisotropic_weights = nullptr, const int* level_limits = nullptr); /*! * \brief Replace the grid with a copy of the \b source, does not copy the acceleration options. * * Using the default inputs is equivalent to the assignment operator, * otherwise this allows to copy all points and inputs of the grid but * only a sub-range of the outputs. * * \param source the grid to copy from. * * \param outputs_begin the first output of the new grid. * \param outputs_end is the first not-included output, i.e., * the logic is similar to std::copy(). * If the last parameter is outside of the range, * then include all outputs from output_begin till * the end of the outputs. */ void copyGrid(const TasmanianSparseGrid *source, int outputs_begin = 0, int outputs_end = -1); /*! * \brief Overload using pass-by-reference as opposed to a pointer. * * The pointer version is supported for backwards compatibility, * this is the preferred way to use the copy command. */ void copyGrid(TasmanianSparseGrid const &source, int outputs_begin = 0, int outputs_end = -1){ copyGrid(&source, outputs_begin, outputs_end); } /*! * \brief Construct a new grid and merge it with the current one. * * This method is used for refinement with user specified anisotropic weights. * As such, it can be called only for global grids with a nested rule. * If there are no loaded points (or if the number of outputs is zero) then this is equivalent to * calling makeGlobalGrid() (i.e., completely replacing the grid) * using the current \b dimensions, \b outputs, and \b rule parameters and the new values for \b depth, \b type, * anisotropic coefficients and level limits. * If there are loaded model values, then the new grid will be added to the existing one without removing any existing points. * * The parameters used and the thrown exceptions are identical to those in the call to makeGlobalGrid(). * In addition, \b std::runtime_error is thrown if the current grid is not Global. */ void updateGlobalGrid(int depth, TypeDepth type, std::vector const &anisotropic_weights, std::vector const &level_limits = std::vector()); /*! * \brief Overload using raw-arrays. * * Array dimensions are not checked, otherwise identical to updateGlobalGrid(). */ void updateGlobalGrid(int depth, TypeDepth type, const int *anisotropic_weights = nullptr, const int *level_limits = nullptr); /*! * \brief Construct a new grid and merge it with the current one. * * This method is used for refinement with user specified anisotropic weights. * If there are no loaded points (or if the number of outputs is zero) then this is equivalent to * calling makeSequenceGrid() (i.e., completely replacing the grid) * using the current \b dimensions, \b outputs, and \b rule parameters and the new values for \b depth, \b type, * anisotropic coefficients and level limits. * If there are loaded model values, then the new grid will be added to the existing one without removing any existing points. * * The parameters used and the thrown exceptions are identical to those in the call to makeSequenceGrid(). * In addition, \b std::runtime_error is thrown if the current grid is not Sequence. */ void updateSequenceGrid(int depth, TypeDepth type, std::vector const &anisotropic_weights, std::vector const &level_limits = std::vector()); /*! * \brief Overload using raw-arrays. * * Array dimensions are not checked, otherwise identical to updateSequenceGrid(). */ void updateSequenceGrid(int depth, TypeDepth type, const int *anisotropic_weights = nullptr, const int *level_limits = nullptr); /*! * \brief Construct a new grid and merge it with the current one. * * This method is used for refinement with user specified anisotropic weights. * If there are no loaded points (or if the number of outputs is zero) then this is equivalent to * calling makeFourierGrid() (i.e., completely replacing the grid) * using the current \b dimensions, \b outputs, and \b rule parameters and the new values for \b depth, \b type, * anisotropic coefficients and level limits. * If there are loaded model values, then the new grid will be added to the existing one without removing any existing points. * * The parameters used and the thrown exceptions are identical to those in the call to makeFourierGrid(). * In addition, \b std::runtime_error is thrown if the current grid is not Fourier. */ void updateFourierGrid(int depth, TypeDepth type, std::vector const &anisotropic_weights, std::vector const &level_limits = std::vector()); /*! * \brief Overload using raw-arrays. * * Array dimensions are not checked, otherwise identical to updateFourierGrid(). */ void updateFourierGrid(int depth, TypeDepth type, const int *anisotropic_weights = nullptr, const int *level_limits = nullptr); /*! * \brief Based on the grid type, calls updateGlobalGrid(), updateSequenceGrid() or updateFourierGrid(). * * \throws std::runtime_error if the grid is not Global, Sequence or Fourier. */ void updateGrid(int depth, TypeDepth type, std::vector const &anisotropic_weights, std::vector const &level_limits = std::vector()); /*! * \brief Overload using raw-arrays. * * Array dimensions are not checked, otherwise identical to updateFourierGrid(). */ void updateGrid(int depth, TypeDepth type, const int *anisotropic_weights = nullptr, const int *level_limits = nullptr); //! \brief Return the \b alpha parameter in the call to makeGlobalGrid(), or return 0 if the grid is not Global. double getAlpha() const{ return (isGlobal()) ? get()->getAlpha() : 0.0; } //! \brief Return the \b beta parameter in the call to makeGlobalGrid(), or return 0 if the grid is not Global. double getBeta() const{ return (isGlobal()) ? get()->getBeta() : 0.0; } //! \brief Return the \b order parameter in the call to makeLocalPolynomialGrid() or makeWaveletGrid(), or return -1 for all other grid types. int getOrder() const{ return (isLocalPolynomial()) ? get()->getOrder() : ((isWavelet()) ? get()->getOrder() : -1); } //! \brief Return the \b dimensions of the grid, i.e., number of model inputs. int getNumDimensions() const{ return (base) ? base->getNumDimensions() : 0; } //! \brief Return the \b outputs of the grid, i.e., number of model outputs. int getNumOutputs() const{ return (base) ? base->getNumOutputs() : 0; } //! \brief Return the underlying TasGrid::TypeOneDRule that gives the points and basis functions. TypeOneDRule getRule() const; /*! * \brief Return the character string that is the description of the user-provided tabulated rule. * * User-provided rules, i.e., Global grids with TasGrid::rule_customtabulated * have a description string that is returned by this method. * All other grids and rules will return an empty string. */ const char* getCustomRuleDescription() const; // used only for Global Grids with rule_customtabulated //! \brief Return the number of points already associated with model values via loadNeededValues(). int getNumLoaded() const{ return (base) ? base->getNumLoaded() : 0; } //! \brief Return the number of points that should be provided to the next call of loadNeededValues(). int getNumNeeded() const{ return (base) ? base->getNumNeeded() : 0; } //! \brief Returns getNumLoaded() if positive, otherwise returns getNumNeeded(), see getPoints(). int getNumPoints() const{ return (base) ? base->getNumPoints() : 0; } /*! * \brief Return the points already associated with model values. * * Returns a vector of size getNumLoaded() times getNumDimensions() * with the coordinates of the loaded points. * The vector is logically divided into strips of length getNumDimensions(), * each strip corresponds to a single point. */ std::vector getLoadedPoints() const{ std::vector x; getLoadedPoints(x); return x; } /*! * \brief Overload that accepts the vector as a parameter. * * The vector is resized to getNumLoaded() times getNumDimensions() and overwritten with the loaded points. * See getLoadedPoints(). */ void getLoadedPoints(std::vector &x) const{ x.resize(Utils::size_mult(getNumDimensions(), getNumLoaded())); getLoadedPoints(x.data()); } /*! * \brief Overload using raw-array, writes the loaded points to the first getNumLoaded() times getNumDimensions() entries of the array. * * Assumes the array size if at least getNumLoaded() times getNumDimensions(), * overwrites the entries with the loaded points in the same format as in getLoadedPoints(). */ void getLoadedPoints(double x[]) const; /*! * \brief Return the points that require model values. * * Returns a vector of size getNumNeeded() times getNumDimensions() * with the coordinates of the needed points. * The vector is logically divided into strips of length getNumDimensions(), * each strip corresponds to a single point. */ std::vector getNeededPoints() const{ std::vector x; getNeededPoints(x); return x; } /*! * \brief Overload that accepts the vector as a parameter. * * The vector is resized to getNumNeeded() times getNumDimensions() and overwritten with the needed points. * See getNeededPoints(). */ void getNeededPoints(std::vector &x) const{ x.resize(Utils::size_mult(getNumDimensions(), getNumNeeded())); getNeededPoints(x.data()); } /*! * \brief Overload using raw-array, writes the loaded points to the first getNumNeeded() times getNumDimensions() entries of the array. * * Assumes the array size if at least getNumNeeded() times getNumDimensions(), * overwrites the entries with the loaded points in the same format as in getNeededPoints(). */ void getNeededPoints(double *x) const; /*! * \brief Returns the loaded points if any, otherwise returns the needed points. * * Grid operations that do not require model values, e.g., getQuadratureWeights(), * operate with the loaded points, but in some cases all points may be needed, * e.g., right after a make method is called. * Thus, points is an alias to the loaded points unless there are no loaded points, * in which case points aliases to the needed points. * The overloads of this method have the same behavior as the corresponding overload * of the other get points methods. * * Note that if getNumPoints() is zero then the grid is empty(). */ std::vector getPoints() const{ std::vector x; getPoints(x); return x; } /*! * \brief Overload that accepts the vector as a parameter. * * See getNeededPoints(). */ void getPoints(std::vector &x) const{ x.resize(Utils::size_mult(getNumDimensions(), getNumPoints())); getPoints(x.data()); } /*! * \brief Overload that accepts the raw array as an input. * * See getNeededPoints(). */ void getPoints(double x[]) const; // returns the loaded points unless no points are loaded, then returns the needed points /*! * \brief Returns a vector of size getNumPoints() of the quadrature weights of the grid. * * The quadrature is designed to work with weight of constant 1 unless the grid * \b rule is associated with a special weight. See TasGrid::TypeOneDRule for details. * * \return A vector of size getNumPoints() holding the quadrature weights; * the order of the weights matches the getPoints(). */ std::vector getQuadratureWeights() const{ std::vector w; getQuadratureWeights(w); return w; } /*! * \brief Overload that accepts the vector as a parameter. * * See getQuadratureWeights(). */ void getQuadratureWeights(std::vector &weights) const{ weights.resize((size_t) getNumPoints()); getQuadratureWeights(weights.data()); } /*! * \brief Overload that accepts the raw array as an input. * * See getQuadratureWeights(). */ void getQuadratureWeights(double weights[]) const; // static memory, assumes that weights has size getNumPoints() /*! * \brief Returns the weights of the model outputs that combine to construct the approximation value at \b x. * * The sum of the model values times the weights will produce the approximation at \b x. * For problems where the model outputs can be represented by a vector, * it is recommended to use loadNeededValues() and evaluate() methods * which have much better performance. * However, not all models can be easily represented as vector valued functions, * e.g., the discretization of the operators in a parametrized partial * differential equation can result in sparse matrices with very different fill. * Therefore, Tasmanian offers the option to compute these weights and leave to the * user to compute the corresponding weighted sum, * e.g., the matrix for each grid point is stored independently and * the action of the parametrized operator onto the vector is approximated * as a weighed linear combination of the individual matrix vector results. * * \param x is a vector of size getNumDimensions() with the coordinates of the point of interest * in the transformed domain. * * \returns A vector of size getNumPoints() with the interpolation weights, * the order of the weights matches the order of the getPoints(). * * Note that using a vector \b x outside of the domain will result in undefined behavior, * but will not throw an exception. * * \throws std::runtime_error if \b x has an incorrect size. */ std::vector getInterpolationWeights(std::vector const &x) const; /*! * \brief Overload that uses raw-array, does not check the array size. * * Identical to getInterpolationWeights() but does not throw if \b x is larger than getNumDimensions(); * however, using shorter \b x is undefined behavior and will likely segfault. */ std::vector getInterpolationWeights(double const x[]) const{ std::vector w((size_t) getNumPoints()); getInterpolationWeights(x, w.data()); return w; } /*! * \brief Overload that uses the vector as a parameter. * * Identical to getInterpolationWeights() but the \b weights vector will be resized * to size getNumPoints() and the entries will be overwritten with the output of getInterpolationWeights(). */ void getInterpolationWeights(const std::vector &x, std::vector &weights) const; /*! * \brief Overload that uses raw-array, does not check the array size. * * Identical to getInterpolationWeights() but does not throw if \b x is larger than getNumDimensions(); * the length of \b x must be at least getNumDimensions() and the length of \b weighs must be at least getNumPoints(). */ void getInterpolationWeights(const double x[], double weights[]) const; /*! * \brief Returns the weights of the model outputs that combine to construct the approximate Jacobian matrix (derivative) at \b x. * * The Jacobian of the k-th output at \b x is the sum of the model values of the k-th output times the Jacobian of the nodal * functions at \b x. * * \param x is a vector of size getNumDimensions() with the coordinates of the point of interest * in the transformed domain. * * \returns A vector of size getNumPoints() * getNumDimensions() with the differentiation weights, * the order of the weights matches the order of the getPoints(). * * Note that using a vector \b x outside of the domain will result in undefined behavior, * but will not throw an exception. * * \throws std::runtime_error if \b x has an incorrect size. */ std::vector getDifferentiationWeights(std::vector const &x) const; /*! * \brief Overload that uses raw-array, does not check the array size. * * Identical to getDifferentiationWeights() but does not throw if \b x is larger than getNumDimensions(); * however, using shorter \b x is undefined behavior and will likely segfault. */ std::vector getDifferentiationWeights(double const x[]) const { std::vector w((size_t) getNumPoints() * (size_t) getNumDimensions()); getDifferentiationWeights(x, w.data()); return w; } /*! * \brief Overload that uses the vector as a parameter. * * Identical to getDifferentiationWeights() but the \b weights vector will be resized to size * getNumPoints() * getNumDimensions() and the entries will be overwritten with the output of getDifferentiationWeights(). */ void getDifferentiationWeights(const std::vector &x, std::vector &weights) const; /*! * \brief Overload that uses raw-array, does not check the array size. * * Identical to getDifferentiationWeights() but does not throw if \b x is larger than getNumDimensions(); * the length of \b x must be at least getNumDimensions() and the length of \b weighs must be at least * getNumPoints() * getNumDimensions(). */ void getDifferentiationWeights(const double x[], double weights[]) const; /*! * \brief Provides the values of the model outputs at the needed points, or overwrites the currently loaded points. * * In order to construct an interpolant, Tasmanian needs the values of the model outputs at each grid point. * If there are needed points (i.e., getNumNeeded() is not zero), then \b vals must correspond to * the model outputs at the needed points, otherwise, it must correspond to the loaded points. * * \param vals A vector that is logically divided into strips of size getNumOutputs() each strip corresponding * to a single point. The order of the outputs must match the order of the points from either * getNeededPoints() or getLoadedPoints(). * If getNumNeeded() is zero, the total size must be getNumOutputs() times getNumLoaded(), * otherwise, it must be getNumOutputs() times getNumNeeded(). * * \throws std::runtime_error if \b vals has an incorrect size. * * \b Note: The needed points can always be cleared with clearRefinement() * and new needed points can be assigned with setAnisotropicRefinement() or setSurplusRefinement(). */ void loadNeededValues(std::vector const &vals); // checks if vals has size num_outputs X getNumNeeded() /*! * \brief Overload that uses a raw-array, does not check the array size. * * Identical to loadNeededPoints() but does not throw if \b vals has an incorrect size (but will segfault). */ void loadNeededValues(const double *vals); /*! * \brief Alias of loadNeededValues(). */ void loadNeededPoints(std::vector const &vals) {loadNeededValues(vals);} /*! * \brief Overload that uses a raw-array, does not check the array size. * * Identical to loadNeededPoints() but does not throw if \b vals has an incorrect size (but will segfault). */ void loadNeededPoints(const double *vals) {loadNeededValues(vals);} /*! * \brief Returns the model values that have been loaded in the gird. * * Returns a pointer to the internal data-structures, which \b must \b not be modified * and will be invalidated by any operation that affects the loaded points, * e.g., mergeRefinement() or loadNeededValues(). * The model values will follow the internal Tasmanian order, identical to getLoadedPoints(). */ const double* getLoadedValues() const{ return (empty()) ? nullptr : base->getLoadedValues(); } /*! * \brief Computes the value of the interpolant (or point-wise approximation) at the given point \b x. * * This is the reference implementation that does not use any acceleration mode even if one is set. * As a result, the calls to evaluate() are thread-safe but potentially slow. * * \param[in] x indicates the coordinate entries of a point within the domain of the sparse grid, * the size must be equal to getNumDimensions(). * \param[out] y will contain the approximated model outputs corresponding to \b x, * the vector will be resized to getNumOutputs(). * * \throws std::runtime_error if \b x has an incorrect size. * * \b Note: calling evaluate() for a point outside of the domain is Mathematically incorrect, * even though no exception will be generated. */ void evaluate(std::vector const &x, std::vector &y) const; /*! * \brief Overload that uses raw-arrays, does not check the array size. * * Identical to evaluate() but does not throw, assumes \b x has size at least getNumDimensions() * and \b y is at least getNumOutputs(), will segfault if either is too short. */ void evaluate(const double x[], double y[]) const; /*! * \brief Computes the value of the interpolant (or point-wise approximation) for a batch of points. * * Identical to calling evaluate() for each point defined by \b x, but uses the specified * acceleration mode and is potentially much faster, see TasGrid::TypeAcceleration for details. * * \tparam FloatType is either \b float or \b double indicating the precision to use. * * \param[in] x is logically divided into strips of size getNumDimensions() defining * the coordinates of points within the sparse grid domain, see also evaluate(). * * \param[out] y is logically divided into \b x.size() / getNumDimensions() number of strips * each with length getNumOutputs(), provides the approximated model outputs for each * point defined by \b x. The vector will be resized, if the original size is incorrect. * * \throws std::runtime_error if instantiated with \b float and the current acceleration * mode is neither CUDA nor MAGMA, see TasGrid::TypeAcceleration. * * \b Notes: this does not check if \b x.size() divides evenly. * * The batch call: * \code * grid.evaluateBatch(x, y); * \endcode * is Mathematically equivalent to: * \code * for(int i=0; i void evaluateBatch(std::vector const &x, std::vector &y) const; /*! * \brief Overload that uses raw-arrays. * * Raw-arrays do not provide size, thus the user must specify the number of points * and the arrays are assumed to have sufficient size (otherwise the call will segfault). * See also evaluate() and evaluateBatch(). * * \param[in] x is logically organized into \b num_x strips of length getNumDimensions(), * each strip will hold the coordinates of a point within the sparse grid domain. * * \param[in] num_x is the total number of points stored in \b x. * * \param[out] y is logically organized into \b num_x strips of length getNumOutputs(), * each strip will be overwritten with the corresponding approximated model outputs. * * The following two calls are equivalent: * \code * grid.evaluateBatch(x, y); // using containers * \endcode * \code * grid.evaluateBatch(x.data(), x.size() / grid.getNumDimensions(), y.data()); // using raw arrays * \endcode */ void evaluateBatch(const double x[], int num_x, double y[]) const; /*! * \brief Overload using single precision and GPU/CUDA acceleration. * * Works identical to the other raw-array overload but works only with CUDA and MAGMA acceleration modes. * * \param[in] x see the double precision array overload * \param[in] num_x see the double precision array overload * \param[in] y see the double precision array overload * * \throws std::runtime_error if the acceleration mode is not CUDA or MAGMA, see TasGrid::TypeAcceleration. * \throws std::runtime_error from failed calls to evaluateBatchGPU(). */ void evaluateBatch(const float x[], int num_x, float y[]) const; /*! * \brief Overload that uses GPU raw-arrays. * * Identical to the raw-array version of evaluateBatch(), but \b gpu_x and \b gpu_y must point * to memory allocated on the CUDA device matching getGPUID(). * Requires that Tasmanian was compiled with CUDA support and CUDA * (or MAGAMA) acceleration mode has been enabled. * * \throws std::runtime_error if Tasmanian was not build with \b -DTasmanian_ENABLE_CUDA=ON. * \throws std::runtime_error if calling for a grid type that doesn't have appropriate CUDA kernels, * e.g., local polynomial or wavelet grids with order more than 2. */ template void evaluateBatchGPU(const FloatType gpu_x[], int cpu_num_x, FloatType gpu_y[]) const; /*! * \brief Equivalent to evaluate() with enabled acceleration or evaluateBatch() with a batch of one point. * * Some use cases still require performance but cannot batch multiple points together. * The evaluateFast() method will work the same as evaluate(), but will use * the specified acceleration mode. * * \b Note: in older versions of Tasmanian, this function used to call a * different set of algorithms optimized for single point evaluations; * currently, evaluateBatch() will automatically switch to the appropriate * mode depending on \b x.size() and \b num_x. * Thus, this method is now an alias to evaluateBatch(). */ template void evaluateFast(const FloatType x[], FloatType y[]) const{ evaluateBatch(x, 1, y); } /*! * \brief Alias to evaluateBatch(). * * Provided for consistency and backwards compatibility. */ template void evaluateFast(std::vector const &x, std::vector &y) const{ evaluateBatch(x, y); } /*! * \brief Computes the integral of each model output over the sparse grid domain. * * The integration weight is assumed 1 unless another weight is associated with * the underlying one dimensional rule, see TasGrid::TypeOneDRule for details. * * \param q will be resized to getNumOutputs() and overwritten with the approximated * integral of each model output. * * The output of integrate() is Mathematically equivalent to calling getQuadratureWeights() * and computing the sum of model values times weights. * However, when the model values have been loaded integrate() is faster and more convenient. */ void integrate(std::vector &q) const; /*! * \brief Overload that uses a raw-array. * * Equivalent to integrate() but \b q must have sufficient size to write the result. * * \param q must have size of at least getNumOutputs(). */ void integrate(double q[]) const; /*! * \brief Overload that returns a vector. */ std::vector integrate() const{ std::vector result; integrate(result); return result; } /*! * \brief Computes the derivative (if available) of the surrogate model at an input point. * * \param x is the point of interest where the Jacobian should be evaluated. * \param jacobian will be resized to getNumOutputs() * getNumDimensions() and overwritten with the Jacobian matrix. */ void differentiate(std::vector const &x, std::vector &jacobian) const; /*! * \brief Same as TasmanianSparseGrid::differentiate() but returns the \b jacobian */ std::vector differentiate(std::vector const &x) const{ std::vector jacobian; differentiate(x, jacobian); return jacobian; } /*! * \brief Overload that uses a raw-array. * * Equivalent to differentiate() but \b jacobian must have sufficient size to write the result. */ void differentiate(const double x[], double jacobian[]) const; //! \brief Returns \b true if the grid is of type global, \b false otherwise. bool isGlobal() const{ return base && base->isGlobal(); } //! \brief Returns \b true if the grid is of type sequence, \b false otherwise. bool isSequence() const{ return base && base->isSequence(); } //! \brief Returns \b true if the grid is of type local polynomial, \b false otherwise. bool isLocalPolynomial() const{ return base && base->isLocalPolynomial(); } //! \brief Returns \b true if the grid is of type wavelet, \b false otherwise. bool isWavelet() const{ return base && base->isWavelet(); } //! \brief Returns \b true if the grid is of type Fourier, \b false otherwise. bool isFourier() const{ return base && base->isFourier(); } //! \brief Returns \b true if the grid is empty (no type), \b false otherwise. bool isEmpty() const{ return !base; } //! \brief Returns \b true if the grid is empty (no type), \b false otherwise. bool empty() const{ return !base; } /*! * \brief Set a linear domain transformation. * * By default integration and interpolation are performed on a canonical interval [-1, 1], * with the exception of Fourier grids using [0, 1] and some Gauss rules, * see TasGrid::TypeOneDRule. * The linear transformation will shift the interval to an arbitrary [a, b] * (or shift and scale for the unbounded case). * Different values can be specified for each dimension and the transformation * will be automatically applied to every operation that uses points, e.g., * getPoints() and evaluate() will return/accept only transformed points. * * Setting or changing the transformation will change the points and weights, * therefore, the transformations should be set immediately after calling a make * command and before calling get-points or computing model values. * Changing the transformation will not throw, but will likely invalidate the loaded data * and should be used with extreme caution (the validity of the underlying Mathematics * is left to the user to analyze). * * \param a with size getNumDimensions() specifies the \b a transformation parameter * for each input * \param b with size getNumDimensions() specifies the \b b transformation parameter * for each input * * \throws std::runtime_error if the grid is empty. * \throws std::invalid_argument if either input has incorrect size. */ void setDomainTransform(std::vector const &a, std::vector const &b); /*! * \brief Overload using raw-arrays. * * Identical to setDomainTransform() but does not check for the size of \b a and \b b, * although it still checks if the grid is empty. */ void setDomainTransform(const double a[], const double b[]); /*! * \brief Returns \b true if a linear domain transformation has been set, \b false otherwise. * * Allows to check if there is a set transformation or if working on the canonical domain. */ bool isSetDomainTransfrom() const; /*! * \brief Removes the domain transformation. * * Use with extreme caution, see setDomainTransform(). */ void clearDomainTransform(); /*! * \brief Returns the two vectors used to call setDomainTransform(). * * If the grid is empty or if no transformation has been set, * this will return empty vectors. * * \param[out] a will be resized to getNumDimensions() and overwritten with the a vector of setDomainTransform(). * \param[out] b will be resized to getNumDimensions() and overwritten with the b vector of setDomainTransform(). * * \b Note: this works the same regardless of which setDomainTransform() overload has been used. */ void getDomainTransform(std::vector &a, std::vector &b) const; /*! * \brief Returns the values of the two vectors used to call setDomainTransform(). * * Assuming that the inputs have sufficient size, will overwrite the getNumDimensions() entries * with the domain transformation. * * \throws std::runtime_error if the grid is empty or if the domain transformation has not been set. * * \b Note: this works the same regardless of which setDomainTransform() overload has been used. */ void getDomainTransform(double a[], double b[]) const; /*! * \brief Set conformal transformation using truncated Maclaurin series of the arcsin() function. * * Conformal transformations apply a non-linear map to the points, weights and basis functions of a grid, * in an attempt to accelerate convergence for some types of functions. * The objective is to expand the area of analytic extension of the target function and thus accelerate convergence; * however, if applied to the wrong function, conformal transformations can deteriorate the accuracy. * Characterizing the functions that would most benefit from conformal maps is an active area of research. * * The truncated Maclaurin series of the arcsin() work well with functions that have a pole close * to the edges of the domain. See:\n * P. Jantsch, C. G. Webster, * Sparse Grid Quadrature Rules Based on Conformal Mappings, * Sparse Grids and Applications - Miami 2016 pp 117--134. * * \param truncation is a vector of size getNumDimensions() that indicates the number of terms * to keep in each direction. The more terms, the more pronounced the transformation becomes; * however, too many terms can in fact produce a pole even worse than the original. */ void setConformalTransformASIN(std::vector const &truncation); //! \brief Returns \b true if conformal transformation has been set. bool isSetConformalTransformASIN() const; //! \brief Removes any currently set transformation. void clearConformalTransform(); //! \brief Fills the array with the values of the set transformation. std::vector getConformalTransformASIN() const; /*! * \brief Removes the currently set level limits. * * Once level limits have been set (by either the make or set-refinement commands), * the limits will be used for all follow-on commands unless either overwritten with a new set of limits * of cleared with this command. */ void clearLevelLimits(){ llimits.clear(); } /*! * \brief Return the currently set level limits. * * Returns the limits that have been set with the last command. * If no limits have been set, an empty vector will be returned. */ std::vector getLevelLimits() const{ return llimits; } /*! * \brief Set refinement using anisotropic estimate for the optimal points. * * Computes the anisotropic coefficients based on the current set of loaded points, * then adds more points to the grid by selecting the points with largest coefficients. * The new points are set to \b needed. See also estimateAnisotropicCoefficients() * * \param type indicates the type of estimate to use, e.g., total degree or curved; * regardless of the specified rule the interpolation estimate is computed (not quadrature). * * \param min_growth is the minimum number of points to add to the grid, e.g., if the model can be executed * in parallel then minimum number of points is needed to ensure occupancy for all computing resources. * The value of \b min_growth can never be less than 1, but the actual number of points * can exceed the \b min_growth depending on the weights and growth of the one dimensional rule. * * \param output indicates which output to use to compute the estimate, using -1 indicates to use all outputs * (possible with Sequence and Fourier grids only, Global grids require a specific output). * * \param level_limits (if not empty) will be used to overwrite the currently set limits. * The limits must be either empty or have size getNumDimensions(); * if empty, the current set of limits will be used. * * \throws std::runtime_error if called during dynamic construction, or there are no loaded points, * or there are no outputs. * * \throws std::invalid_argument if \b min_growth is not positive, \b output is out of range, * or \b level_limits has the wrong size. */ void setAnisotropicRefinement(TypeDepth type, int min_growth, int output, const std::vector &level_limits); /*! * \brief Overload using raw-array. * * Identical to setAnisotropicRefinement() with the exception that level_limits is a raw array, * empty is equivalent to \b nullptr and the size is not checked. */ void setAnisotropicRefinement(TypeDepth type, int min_growth, int output, const int *level_limits = nullptr); /*! * \brief Call setAnisotropicRefinement() and then getNeededPoints(). */ std::vector getAnisotropicRefinement(TypeDepth type, int min_growth, int output, const std::vector &level_limits) { setAnisotropicRefinement(type, min_growth, output, level_limits); return getNeededPoints(); } /*! * \brief Estimate the anisotropic rates of coefficient decay for different direction. * * Available for Global, Sequence and Fourier grids, the anisotropic coefficients describe the space * of the dominant basis functions needed to construct optimal approximation to the model. * See the documentation of TasGrid::TypeDepth of the different formulas. * The estimate requires that values have been loaded in the grid, i.e., * getNumOutputs() > 0 and getNumLoaded() > 0. * * \param type is the assumed type of optimal space, i.e., total degree, total degree with log-correction, or hyperbolic cross section. * \param output determines the output to use for the inference of the coefficients, * for Global grid it must be between 0 and getNumOutputs() -1, in other cases, * it can also be set to -1 to indicate "all outputs" or for each basis use the larges coefficient among all outputs. * * \returns the \b xi and \b eta (if used) parameters of the estimate indicated by \b type. * * \throws std::runtime_error if the grid is empty, has no outputs or no loaded points. * \throws std::invalid_argument if the output is out of range. */ std::vector estimateAnisotropicCoefficients(TypeDepth type, int output) const{ std::vector w; estimateAnisotropicCoefficients(type, output, w); return w; } /*! * \brief Overload that writes the result to a parameter. * * The inputs are equivalent to estimateAnisotropicCoefficients() * but the result is returned into \b weights. */ void estimateAnisotropicCoefficients(TypeDepth type, int output, std::vector &weights) const; /*! * \brief Refine the grid based on the surplus coefficients, Sequence grids and Global grids with a sequence rule. * * Using the relative magnitude of the surplus coefficients, add more points to the grid * and set them to needed. The approach differs from the local (polynomial or wavelet) case * in the interpretation of the surpluses, instead of local-spacial estimate * the surpluses are interpreted as indicators of needed polynomial basis functions. * * \param tolerance indicates the cutoff threshold for refinement, points will not be * included once the magnitude of the relative surplus drops below the tolerance. * \param output indicates the output to use for the surpluses, the Sequence grid * accepts -1 to indicate the use of all outputs. * \param level_limits indicates a new set of limits, if empty the currently set limits * will be used. * * \throws std::runtime_error if the called during the construction process, if the grid is empty, * of if the grid has no outputs or values. * \throws std::invalid_argument if the \b output is out of range, \b tolerance is negative, * or if the \b level_limits has the wrong size. */ void setSurplusRefinement(double tolerance, int output, std::vector const &level_limits); //! \brief Overload that uses array for the level limits. void setSurplusRefinement(double tolerance, int output, const int *level_limits = nullptr); /*! * \brief Call setSurplusRefinement() for Sequence and Global grids with a sequence rule and then getNeededPoints(). */ std::vector getSurplusRefinement(double tolerance, int output, std::vector const &level_limits) { setSurplusRefinement(tolerance, output, level_limits); return getNeededPoints(); } /*! * \brief Refine the grid based on the surplus coefficients, Local-Polynomial and Wavelet grids. * * Using the relative magnitude of the surplus coefficients, add more points to the grid * and set them to needed. This method uses the hierarchical and local structure of the one dimensional * rule and interprets the surplus as a local error indicator. * The refinement can be combined with tests for completeness of the hierarchy * (prioritizing parents or even the entire ancestry) or local anisotropy that * can manifest even in globally isotropic cases. See TasGrid::TypeRefinement * for details. * * If this method is called on a Global or a Sequence grid, the \b criteria will be ignored * and the method will use the Global/Sequence variant. * * \param tolerance indicates the cutoff threshold for refinement, points will not be * included once the magnitude of the relative surplus drops below the tolerance. * \param criteria indicates how to prioritize the hierarchy and/or local anisotropy. * \param output indicates a specific output to use for the refinement, by default (when -1) * all model outputs will be considered together. * \param level_limits indicates a new set of limits, if empty the currently set limits * will be used. * \param scale_correction is a set of weights that would multiply the surpluses before * the tolerance test; the correction can be used to modify the threshold test (e.g., * multiply the surplus by the integral of the basis functions) or to guide * the refinement towards certain regions of the domain. * The values of the correction terms are organized in order that matches the order * of getNumLoaded() and there is one weight per active output (either 1 or getNumOutputs() * depending whether \b output is -1 or positive). * If the scale correction is empty, then no correction is used (i.e., using correction of 1.0). * * \throws std::runtime_error if called during construction, or if the grid is empty or has no * outputs or loaded points, of if the grid has incompatible type (not local polynomial or wavelet). * * \throws std::invalid_argument if \b output is out of range, of if the level limits and/or * scale correction have incorrect size. */ void setSurplusRefinement(double tolerance, TypeRefinement criteria, int output, std::vector const &level_limits, std::vector const &scale_correction = std::vector()); // -1 indicates using all outputs /*! * \brief Overload that uses raw-arrays. * * The \b scale_correction is a potentially large vector and using a raw array avoids a large data-copy * when calling from C/Python/Fortran interfaces. * Otherwise the method behaves the same, but does not throw if the arrays have incorrect size (will probably segfault). */ void setSurplusRefinement(double tolerance, TypeRefinement criteria, int output = -1, const int *level_limits = nullptr, const double *scale_correction = nullptr); /*! * \brief Call setSurplusRefinement() for Local-Polynomial and Wavelet grids and then getNeededPoints(). */ std::vector getSurplusRefinement(double tolerance, TypeRefinement criteria, int output, std::vector const &level_limits, std::vector const &scale_correction = std::vector()) { setSurplusRefinement(tolerance, criteria, output, level_limits, scale_correction); return getNeededPoints(); } /*! * \brief Remove all needed points from the grid. * * Once a refinement is set, but before the new values have been loaded, the refinement can be canceled * with this command. After this call, all needed points will be erased. */ void clearRefinement(); /*! * \brief Merges the loaded and needed points into a single grid, resets all loaded values to zero. * * This method allows refinement to be used in cases where the model values cannot be computed at the grid points, * e.g., when working with random or unstructured data. * Once a refinement is set, the new points can be merged without model values which will result in a larger grid * with all (previous and new) loaded values reset to 0.0. Afterwards, the setHierarchicalCoefficients() method * can be used to set a new set of coefficients, e.g., inferred from the data and the hierarchical basis values. */ void mergeRefinement(); // merges all points but resets all loaded values to 0.0 /*! * \brief Begin a dynamic construction procedure. * * Initializes the internal data-structures needed for the construction procedure (which is pretty cheap) * and makes a call to \b clearRefinement(). * * \b Note: after this call, setSurplusRefinement() and setAnisotropicRefinement() * cannot be called until finishConstruction() is issued. * * \b Note: the construction process can be initiated before any model values have been loaded, * in such case, the initial set of points will always come first in a call to getCandidateConstructionPoints(). */ void beginConstruction(); /*! * \brief Returns \b true if the dynamic construction procedure has been initialized, \b false otherwise. * * Simply returns the internal flag. */ bool isUsingConstruction() const{ return using_dynamic_construction; } /*! * \brief Generate a sorted list of points weighted by descending importance. * * The \e importance is inferred from the user provided anisotropic weighs * using the formula specified by the \b type, see TasGrid::TypeDepth. * The full tensor types will fallback to \b type_level. * * Unlike the batch procedures in setAnisotropicRefinement(), there is no expectation that * the entire batch is processed, in fact only a small subset of the most important * points should be computed and loaded, then the getCandidateConstructionPoints() * should be called again and it will return an updated list of points. * Enough points should be used from the top of the list to ensure occupancy across * computing resources, e.g., CPU cores or MPI ranks, * but the bottom set of points will contribute less and less to the overall accuracy. * * \param type sets the formula to use when weighting the potential points, see TasGrid::TypeDepth. * \param anisotropic_weights are the xi and eta parameters for the formula, * the vector must have the correct size, either getNumDimensions() or twice * as much to handle the curved weights. * \param level_limits (if not empty) will be used to overwrite the currently set limits. * The limits must be either empty or have size getNumDimensions(); * if empty, the current set of limits will be used. * * \returns A vector organized in strips of length getNumDimensions() that indicate * the coordinates of the points to use as model inputs, unlike the getPoints() * command, the points here are arranged in decreasing importance. * * \throws std::runtime_error if the grid is empty, Local Polynomial or this is called before beginConstruction(). * * \throws std::invalid_argument if the \b anisotropic_weights or \b level_limits have incorrect size. */ std::vector getCandidateConstructionPoints(TypeDepth type, std::vector const &anisotropic_weights = std::vector(), std::vector const &level_limits = std::vector()); /*! * \brief Essentially the same as \b getCandidateConstructionPoints() but the weights are obtained from a call to \b estimateAnisotropicCoefficients(). * * This method is the construction equivalent to setAnisotropicRefinement(). * One notable difference is that this function will not throw if there are no loaded points, * instead isotropic coefficient will be used * until enough points are loaded so that estimates for the coefficients can be computed. * * \param type sets the formula to use when weighting the potential points, see TasGrid::TypeDepth. * \param output indicates which coefficients will be used to estimate the anisotropic decay rate, * when working with Sequence and Fourier grids this can be set to -1 to use all outputs. * \param level_limits (if not empty) will be used to overwrite the currently set limits. * The limits must be either empty or have size getNumDimensions(); * if empty, the current set of limits will be used. * * \returns a vector organized in strips of length getNumDimensions() that indicate * the coordinates of the points to use as model inputs, unlike the getPoints() * command, the points here are arranged in decreasing importance. * * \throws std::runtime_error if the grid is empty, Local Polynomial or this is called before beginConstruction(). * * \throws std::invalid_argument if the \b level_limits have incorrect size or \b output is out of range. */ std::vector getCandidateConstructionPoints(TypeDepth type, int output, std::vector const &level_limits = std::vector()); /*! * \brief Returns a sorted list of points weighted by descending importance using the hierarchical surpluses. * * This is the construction equivalent to the Local Polynomial setSurplusRefinement(). * The inputs are the same as setSurplusRefinement() except the returned points will be sorted by * decreasing surpluses. Similar to the other getCandidateConstructionPoints() overloads, * this can be called before any model values have been loaded. */ std::vector getCandidateConstructionPoints(double tolerance, TypeRefinement criteria, int output = -1, std::vector const &level_limits = std::vector(), std::vector const &scale_correction = std::vector()); /*! * \brief Add pairs of points with associated model values. * * This is the construction equivalent to loadNeededValues(), the main difference is that any * number of points can be loaded here and the points can be in any arbitrary order * (they have to correspond to the model values in this call only). * * \param x is a vector with strips of size getNumDimensions() indicating the points where the model * values were computed. The points do not have to be in any order; however, every point has to match * a potential grid points. * \param y is a vector with strips of size getNumOutputs() indicating the model outputs corresponding * each of the provided points. * * \throws std::runtime_error if the number of strips in \b y are less than those in \b x. * * \b Note: regardless of the grid type and rule, as the depth/level increases the points become dense * in the domain; thus every point is theoretically a potential grid points. * However, if a random point is chosen than the level may easily overflow the range of the \b int type, * the safest option is to make sure the points match the ones returned by getCandidateConstructionPoints(). */ void loadConstructedPoints(std::vector const &x, std::vector const &y); /*! * \brief Same as \b loadConstructedPoint() but using arrays in place of vectors (array size is not checked) * * Does not throw on incorrect array size, but will likely segfault. */ void loadConstructedPoints(const double x[], int numx, const double y[]); /*! * \brief End the procedure, clears flags and unused constructed points, can go back to using regular refinement * * After this call, the construction methods getCandidateConstructionPoints() and loadConstructedPoint() * cannot be used until a new call to beginConstruction(). * * \b Note: finalizing the construction process can potentially lead to loss of data. * The constructed points can be loaded in any order, but the points need to satisfy constraints * before being incorporated within a grid. Some grids require that points form a lower complete set, * or the point must form a connected graph, or there must be enough points to complete a tensor * (when the rules grow by more than one point). In such scenarios, the points and values are stored * in a temporary structure until enough data is present to add them to the grid. * Finalizing the construction will delete all data for points that have not been incorporated yet. */ void finishConstruction(); /*! * \brief Return a reference to the internal data-structure that stores the hierarchical coefficients. * * All types of grids (except Global grids), use a hierarchical basis representation where the interpolant * is expressed as a set of coefficients times the basis functions. * For Local Polynomial and Wavelet grids, the coefficients are commonly known as hierarchical surpluses; * for Sequence grid, the coefficients correspond to the Newton polynomials; * for Fourier grids, the coefficients are the linear combination of discrete Fourier transform coefficients. * * The returned array has getNumLoaded() strips of size getNumOutputs() where each strip corresponds to * one basis function. In the case of Fourier grids, the coefficients are complex numbers and * (for performance reasons) the real and complex parts are stored separately, i.e., * the first getNumLoaded() strips hold the real parts and there is a second set of getNumLoaded() * strips that hold the complex components. If the grid is empty or there are no outputs or * no loaded points, then this returns \b nullptr. * * \b Note: modifying the coefficients through this pointer leads to undefined behavior, * use setHierarchicalCoefficients() instead. */ const double* getHierarchicalCoefficients() const; /*! * \internal * \brief Copies the coefficients to the pre-allocated array, intended for internal use. * \endinternal */ void getHierarchicalCoefficientsStatic(double *coeff) const{ std::copy(getHierarchicalCoefficients(), getHierarchicalCoefficients() + ((isFourier()) ? 2 : 1) * getNumOutputs() * getNumLoaded(), coeff); } /*! * \brief Overwrites the current set of coefficients (and loaded values) with the ones provided. * * Discards the current set of loaded values and the associated hierarchical coefficients, * and replaces both with the data provided here. The coefficients are overwritten, * while the values are inferred, i.e., the opposed from the use case of loadNeededValues() * where the model values are provided and the coefficients are computed. * * \param c is a vector of getNumLoaded() strips of size getNumOutputs(), * each strip corresponds to the coefficients of one basis function. * Fourier coefficients are an exceptions as they require twice as many strips where the * first set corresponds to the real components and the second set corresponds to the * complex components of the coefficients. * * \throws std::runtime_error is the number of coefficients is incorrect. */ void setHierarchicalCoefficients(const std::vector &c); /*! * \brief Overload that uses raw-arrays. * * Identical to setHierarchicalCoefficients() but does not check for the size of the array. */ void setHierarchicalCoefficients(const double c[]){ base->setHierarchicalCoefficients(c); } /*! * \brief Computes the values of the hierarchical function basis at the specified points. * * The method for getInterpolationWeights() computes the values of the nodal basis function, * e.g., Lagrange polynomials, while this computes the values of the hierarchical functions, e.g., * Newton polynomials. The call is optimized for multiple points at a time. * The output consists of strips of size getNumPoints() and one strip corresponds to one * point provided in \b x. Effectively this constructs a matrix in column major format * where each column corresponds to a single input point \b x and each row corresponds * to a single grid point. * * When working with Fourier grids, the real and complex part of each basis is interlaced, * i.e., the strip size is twice as large; see the array overload. * * \param[in] x has strips of size getNumDimensions() indicating a point in the domain * where the basis is to be computed. * * \param[out] y will have the same number of strips with size getNumPoints() * (or twice that to accommodate the real and complex parts of the basis). * * \b Note: if the the output from getHierarchicalCoefficients() is interpreted as * a matrix in column major format with leading dimension of getNumOutputs(), * and if the output of this call is interpreted as a matrix in column major * format with leading dimension getNumPoints(), then the result of the product * of the coefficients times the basis will be equal to the result of evaluateBatch(). */ void evaluateHierarchicalFunctions(std::vector const &x, std::vector &y) const; /*! * \brief Overload that returns the result. * * Useful for direct initialization of vectors. */ std::vector evaluateHierarchicalFunctions(std::vector const &x) const{ std::vector y; evaluateHierarchicalFunctions(x, y); return y; } /*! * \brief Array overload, the inputs must have pre-allocated and correct size. * * The size of \b x must be \b num_x times getNumDimensions() and the size of \b y * must be \b num_x times getNumPoints() (or twice that for the Fourier grids). * * Example of returning the result in a vector of complex numbers: * \code * TasGrid::TasmanianSparseGrid grid = TasGrid::makeFourierGrid(...); * int num_x = ...; // set the number of points * std::vector x(grid.getNumDimensions() * num_x); * // initialize x * std::vector> y(grid.getNumPoints() * num_x); * grid.evaluateHierarchicalFunctions(x.data(), num_x, reinterpret_cast(y.data())); * // at this point y is loaded with the complex numbers * \endcode */ void evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const; /*! * \brief Constructs a sparse matrix with the values of the hierarchical basis functions. * * The local basis functions associated with Local Polynomial and Wavelet grids * means that only a small set of the basis functions will be non-zero at any * given point in the domain. Effectively, the matrix build by * evaluateHierarchicalFunctions() will be sparse. * This method generates the sparse matrix in compressed format in non-zeroes per entry in \b x. * * \param[in] x has strips of size getNumDimensions() indicating a point in the domain * where the basis is to be computed. * \param[out] pntr will have size one more than the number of strips in \b x, * pntr[i] indicate the starting offsets of the entries for the i-th point, * (the first entry will always be zero) and pntr.back() is the total number of non-zeros. * \param[out] indx holds the indexes of the supported basis functions, * i.e., indx[pntr[i]] ... indx[pntr[i+1] - 1] are the indexes of the basis functions * supported over the i-th point. * \param[out] vals are the numeric values of the basis functions corresponding to * the indexes in \b indx. */ void evaluateSparseHierarchicalFunctions(const std::vector &x, std::vector &pntr, std::vector &indx, std::vector &vals) const; /*! * \brief Returns the support of the hierarchical functions. * * The Global, Sequence and Fourier grids rely on basis functions with support over the entire domain. * However, local-polynomial and wavelet grids have basis that is restricted to a hypercube centered * at the corresponding point and with equal support in each direction. * This method returns the length for each basis function and direction. * * \returns either an empty vector (for an empty grid), or a vector of size getNumDimensions() times * getNumPoints() organized in strips of length getNumDimensions(). * Each strip corresponds to a basis function and if (in a some direction for some basis function) * an x-point falls away from the corresponding grid point at a distance larger than the support, * then the basis will evaluate to zero. * * \b Note: the support of all basis functions is logically restricted to the grid domain, * i.e., the effective support equals the intersection of the hypercube and the domain. */ std::vector getHierarchicalSupport() const; /*! * \brief Returns the integrals of the hierarchical basis functions. * * Returns a vector of size getNumPoints() that holds the integral of each * basis function. If the output of getHierarchicalCoefficients() is interpreted as a matrix, * the product of that matrix times this vector is the same as the output of TasmanianSparseGrid::integrate(). * * One use case of the integrals is to add scale correction to the surplus refinement, * e.g., rescale the coefficients by the integral of the basis function: * \code * auto grid = TasGrid::makeLocalPolynomialGrid(...); * // ... load values ... // * auto correction = grid.integrateHierarchicalFunctions(); * grid.setSurplusRefinement(1.E-4, TasGrid::refine_classic, 0, {}, correction); * \endcode */ std::vector integrateHierarchicalFunctions() const{ std::vector integrals; integrateHierarchicalFunctions(integrals); return integrals; } /*! * \brief Overload where the vector is passes as a parameter. * * \param integrals will be resized to getNumPoints() and overwritten with * the integrals of the hierarchical basis functions. */ void integrateHierarchicalFunctions(std::vector &integrals) const{ integrals.resize(getNumPoints()); integrateHierarchicalFunctions(integrals.data()); } /*! * \brief Overload using raw-arrays. * * Useful mostly for the C/Python/Fortran interfaces. * * \param integrals must have size getNumPoints() and will be overwritten with * the integrals of the hierarchical basis functions. */ void integrateHierarchicalFunctions(double integrals[]) const; /*! * \brief Returns the powers of the polynomial that span the effective basis, Global and Sequence grids only. * * Different rules have different growth in number of points and different exactness * with respect to integration and interpolation. * This method returns the actual polynomial space spanned by the basis used in the grid. * * \param interpolation determines whether to look for the space of exactly interpolated * polynomials (\b true), or the space of exactly integrated polynomials (\b false). * * \returns a vector with getNumPoints() number of strips each having getNumDimensions() entries, * each integer corresponds to the polynomial power in that direction, e.g., * for a two dimensional grid (0, 0, 1, 0) indicates the constant in all directions * and linear in the first input constant in the second. * * \throws std::runtime_error if the grid is not Global or Sequence. */ std::vector getGlobalPolynomialSpace(bool interpolation) const; /*! * \brief Prints short human-readable text describing the grid properties. * * Among the outputs are type of the grid, number of inputs/outputs/points, * one dimensional rule, and currently selected acceleration type. * * \param os indicates the stream to use for the text output, * defaults to std::cout. */ void printStats(std::ostream &os = std::cout) const; /*! * \brief Change the current acceleration mode to the one specified. * * Sets a new acceleration mode and releases the cached data-structures for the old mode. * * \param acc is the new acceleration mode, see TasGrid::TypeAcceleration. * * \b Note: any acceleration method can be set regardless whether it is available. * If the selected mode has not been enabled in CMake, this will select the * "next-best" mode, thus enableAcceleration() is a suggestion rather than a hard request. * See getAccelerationType(). */ void enableAcceleration(TypeAcceleration acc); /*! * \brief Combines calls the enableAcceleration(), getGPUID() and allows for user provided handles. * * The purpose of this method is to allow for one-show setup of the acceleration mode and gpu_id. * * \param acc is a new acceleration mode, see TasGrid::TypeAcceleration. * \param new_gpu_id is the new device id to use for acceleration, the number must be between 0 and getNumGPUs() - 1. */ void enableAcceleration(TypeAcceleration acc, int new_gpu_id); /*! * \brief Set the preferred back-end algorithm for Local Polynomial grids. * * Usually the Local Polynomial grids use sparse data-structures and sparse linear algebra, * but if the fill not sufficiently small then dense methods can yield better performance * at the expense of higher memory footprint. * In TasGrid::accel_cpu_blas mode, the dense algorithm will be used when the fill increases * above the 10% threshold. In CUDA mode, even if the fill is computed, switching modes * incurs a large overhead and thus the sparse algorithm is always favored. * Sparse computations work better on newer GPU architectures (e.g., Pascal and Volta) * and consumer (gaming) cards with reduced double-precision capabilities, * but older devices coupled with small grids may work better with the dense algorithm. * Hence, Tasmanian includes the manual option to select the desired algorithm. * * \param favor if set to \b true will force the sparse back-end, if set to \b false will * force the dense back-end. If the mode has been forced already, calling the method * with the converse \b favor will reset mode to the default (automatic) selection. */ void favorSparseAcceleration(bool favor); /*! * \brief Takes a user provided cuBlas handle. * * \param handle must be a valid and initialized cublasHandle_t * * \throws std::runtime_error if CUDA is not enabled in CMake and enableAcceleration() */ void setCuBlasHandle(void *handle); /*! * \brief Takes a user provided cuSparse handle. * * \param handle must be a valid and initialized cusparseHandle_t * * \throws std::runtime_error if CUDA is not enabled in CMake and enableAcceleration() */ void setCuSparseHandle(void *handle); /*! * \brief Takes a user provided cuSparse handle. * * \param handle must be a valid and initialized cusolverDnHandle_t * * \throws std::runtime_error if CUDA is not enabled in CMake and enableAcceleration() */ void setCuSolverHandle(void *handle); /*! * \brief Takes a user provided cuBlas handle. * * \param handle must be a valid and initialized rocblas_handle * * \throws std::runtime_error if HIP is not enabled in CMake and enableAcceleration() */ void setRocBlasHandle(void *handle); /*! * \brief Takes a user provided cuSparse handle. * * \param handle must be a valid and initialized rocsparse_handle * * \throws std::runtime_error if HIP is not enabled in CMake and enableAcceleration() */ void setRocSparseHandle(void *handle); /*! * \brief Takes a user provided sycl::queue handle. * * \param queue must be a valid and initialized sycl::queue * * \throws std::runtime_error if DPC++ is not enabled in CMake and enableAcceleration() */ void setSycleQueue(void *queue); /*! * \brief Returns the current effective acceleration mode. * * Returns the acceleration mode that will be used, i.e., the one selected internally * based on the request made in enableAcceleration(). */ TypeAcceleration getAccelerationType() const{ return acceleration->mode; } /*! * \brief Returns whether a specific mode can be enabled. * * Based on the CMake compile time options, this method returns \b true * for all acceleration modes that will be enabled, and \b false for all * modes that will be replaced by a fallback alternative. */ static bool isAccelerationAvailable(TypeAcceleration acc); /*! * \brief Select the current CUDA device. * * Select the CUDA device to be used for the CUDA acceleration types, * default device is \b 0. * \param new_gpu_id is the CUDA device ID of the new device, * the number is between 0 and getNumGPUs() - 1. * * \throws std::runtime_error if the \b new_gpu_id is out of range. */ void setGPUID(int new_gpu_id); /*! * \brief Returns the currently set CUDA device. * * Does not throw if CUDA is not enabled in CMake, instead the default \b 0 is returned. */ int getGPUID() const{ return acceleration->device; } /*! * \brief Return the number of visible CUDA devices. * * Simple wrapper to cudaGetDeviceCount(). * * Use the \b tasgrid command line tool to see all available devices: * \code * tasgrid -v * \endcode */ static int getNumGPUs(){ return AccelerationMeta::getNumGpuDevices(); } /*! * \brief Return the available device memory, in units of MB. * * Simple wrapper to cudaGetDeviceProperties() returning totalGlobalMem divided by 2^20. * \param gpu is the CUDA device ID to be queried, if the device is out of range * then \b 0 will be returned (i.e., Tasmanian will not throw). */ static int getGPUMemory(int gpu); /*! * \brief Return the CUDA device name. * * Simple wrapper to cudaGetDeviceProperties() returning "name". * \param gpu is the CUDA device ID to be queried, if the device is out of range * then empty string will be returned (i.e., Tasmanian will not throw). * \returns the CUDA device name. */ static std::string getGPUName(int gpu); /*! * \brief Computes the values of the hierarchical function basis at the specified points (CUDA version). * * Equivalent to evaluateHierarchicalFunctions() but using arrays allocated on the CUDA device. * \tparam FloatType must be either float or double to indicate the precision used by the CUDA kernels. * * \param gpu_x must have size getNumDimensions() times \b cpu_num_x and must be allocated on * the currently set CUDA device. * \param cpu_num_x is an integer (located on the CPU memory) indicating the number of points. * \param gpu_y must have size getNumPoints() times \b cpu_num_x and must be allocated on * the currently set CUDA device. * * \throws std::runtime_error if the grid is Global or Wavelet or if the currently set acceleration mode * is not compatible, i.e., TasGrid::accel_none or TasGrid::accel_cpu_blas. * Also, if CUDA has not been enabled at compile time. * * \b Note: will not work for LocalPolynomial grids with order bigger than 2 or Wavelets with order 3. */ template void evaluateHierarchicalFunctionsGPU(const FloatType gpu_x[], int cpu_num_x, FloatType gpu_y[]) const; /*! * \brief Computes the values of the hierarchical function basis at the specified points (sparse/CUDA version). * * Equivalent to evaluateSparseHierarchicalFunctions() but using arrays allocated on the CUDA device. * \tparam FloatType must be either float or double to indicate the precision used by the CUDA kernels. * * \param[in] gpu_x must have size getNumDimensions() times \b cpu_num_x and must be allocated on * the currently set CUDA device. * \param[in] cpu_num_x is an integer (located on the CPU memory) indicating the number of points. * \param[out] gpu_pntr will be allocated to size \b cpu_num_x + 1 and will hold the offsets of * indexes for each point, the current memory will not be freed. * \param[out] gpu_indx will be allocated to the number of non-zeros and will hold the indexes * of the non-zeros for each point, the current memory will not be freed. * \param[out] gpu_vals will be allocated to the number of non-zeros and will hold the non-zero * values of the basis function, the current memory will not be freed. * \param[out] num_nz is an integer located on the CPU, will be overwritten to the total * number of non-zeros. * * \throws std::runtime_error if the grid is not Local Polynomial or if the currently set acceleration mode * is not compatible, i.e., TasGrid::accel_none or TasGrid::accel_cpu_blas. * Also, if CUDA has not been enabled at compile time. * * \b Note: will not work for LocalPolynomial grids with order bigger than 2. */ template void evaluateSparseHierarchicalFunctionsGPU(const FloatType gpu_x[], int cpu_num_x, int* &gpu_pntr, int* &gpu_indx, FloatType* &gpu_vals, int &num_nz) const; //! \brief Signature compatible with TasDREAM::DreamPDF, TasDREAM::DreamModel amd TasDREAM::DreamMergedLikelyModel. using EvaluateCallable = std::function const&, std::vector&)>; /*! * \brief Custom conversion to a callable method using the TasDREAM::DreamPDF signature. * * This conversion allows an instance of TasmanianSparseGrid to be passed as input * to any method that expects TasDREAM::DreamPDF, TasDREAM::DreamModel or TasDREAM::DreamMergedLikelyModel. */ operator EvaluateCallable() const{ return [&](std::vector const &x, std::vector &y)->void{ evaluateBatch(x, y); }; } //! \brief Signature of the domain inside lambda, identical to TasDREAM::DreamDomain. using DomainInsideSignature = std::function const &)>; // trick for Doxygen formatting purposes /*! * \brief Returns a lambda object that satisfies the TasDREAM::DreamDomain signature. * * This method allows for the domain currently set in the grid to be passed to the * Tasmanian DREAM sampling templates in place of the \b inside() object. */ DomainInsideSignature getDomainInside() const{ auto rule = getRule(); if ((rule == TasGrid::rule_gausshermite) || (rule == TasGrid::rule_gausshermiteodd)){ // unbounded domain return [](std::vector const &)->bool{ return true; }; }else if ((rule == TasGrid::rule_gausslaguerre) || (rule == TasGrid::rule_gausslaguerreodd)){ // bounded from below if (domain_transform_a.empty()){ return [](std::vector const &x)->bool{ for(auto const &v : x) if (v < 0.0) return false; return true; }; }else{ size_t dims = (size_t) getNumDimensions(); return [=](std::vector const &x)->bool{ for(size_t i=0; i const &x)->bool{ for(auto const &v : x) if ((v < 0.0) || (v > 1.0)) return false; return true; }; }else{ return [](std::vector const &x)->bool{ for(auto const &v : x) if ((v < -1.0) || (v > 1.0)) return false; return true; }; } }else{ size_t dims = (size_t) getNumDimensions(); return [=](std::vector const &x)->bool{ for(size_t i=0; i domain_transform_b[i])) return false; return true; }; } } } /*! * \brief Removes all points from the grid that have relative surplus less than the \b tolerance. * * The \b output and \b scale_correction variables have the same effects as in the call to setSurplusRefinement(). * The purpose of this call is to reduce the number of points and thus the memory footprint of the grid. * As such, points will be removed with no regard of preserving lower completeness or connectivity of the hierarchical graphs; * therefore, it is possible that the grid no longer has a valid state with respect to the update and refinement algorithms. * Calling loadNeededValues() or any refinement or construction method after the removal of points may lead to undefined behavior; * get, evaluate and file I/O methods are safe to call. * * \param tolerance the cut-off tolerance for the point removal. * \param output is the output to use for the tolerance test, can be set to -1 to use all outputs. * \param scale_correction is the same as in the call to setSurplusRefinement(). * * \throws std::runtime_error if the grid is not Local Polynomial. */ void removePointsByHierarchicalCoefficient(double tolerance, int output = -1, const double *scale_correction = nullptr); /*! * \brief Keeps only the given number of points with largest scaled surpluses. * * Similar to removePointsByHierarchicalCoefficient(), but the points are not removed based on a comparison to a tolerance. * Instead, only the given number of points is kept so that the remaining points have the largest scaled surplus coefficients. * * \param num_new_points the number of points to keep in the grid. * \param output is the output to use for the tolerance test, can be set to -1 to use all outputs. * \param scale_correction is the same as in the call to setSurplusRefinement(). * * \throws std::runtime_error if the grid is not Local Polynomial. */ void removePointsByHierarchicalCoefficient(int num_new_points, int output = -1, const double *scale_correction = nullptr); #ifndef __TASMANIAN_DOXYGEN_SKIP_INTERNAL /*! * \internal * \brief Count the number of non-zeros in a call to evaluateSparseHierarchicalFunctions(). * * Used by the C/Python/Fortran interfaces, counts the number of non-zeros so memory * can be pre-allocated by the corresponding language before a call to evaluateSparseHierarchicalFunctionsStatic(). * \endinternal */ int evaluateSparseHierarchicalFunctionsGetNZ(const double x[], int num_x) const; /*! * \internal * \brief Assumes pre-allocated arrays, otherwise identical to evaluateSparseHierarchicalFunctions() * * See evaluateSparseHierarchicalFunctionsGetNZ(). * \endinternal */ void evaluateSparseHierarchicalFunctionsStatic(const double x[], int num_x, int pntr[], int indx[], double vals[]) const; /*! * \internal * \brief Return a reference to the multi-indexes of the loaded points. * * Testing and debugging purposes mostly. * \endinternal */ const int* getPointsIndexes() const; /*! * \internal * \brief Return a reference to the multi-indexes of the needed points. * * Testing and debugging purposes mostly. * \endinternal */ const int* getNeededIndexes() const; /*! * \internal * \brief Return a reference to the internal grid. * * Casts the internal unique_ptr to \b T and returns the result. * \endinternal */ template inline T* get(){ return dynamic_cast(base.get()); } /*! * \internal * \brief Overload using const. * * Same as get(), but the method is const and returns a const reference. * \endinternal */ template inline T const* get() const{ return dynamic_cast(base.get()); } /*! * \internal * \brief Allows the addon methods to use the acceleration context. * * \endinternal */ AccelerationContext const* getAccelerationContext() const{ return acceleration.get(); } #endif // __TASMANIAN_DOXYGEN_SKIP_INTERNAL protected: #ifndef __TASMANIAN_DOXYGEN_SKIP_INTERNAL /*! * \internal * \brief Reset the grid to empty. * * Resets the grid, all cache data structures, and the acceleration mode. * \endinternal */ void clear(); /*! * \internal * \brief Maps canonical points to the transformed equivalent. * * Given an array of canonical points \b x with size \b num_points and \b num_dimensions for given \b rule, * convert them to transformed points applying only the linear transform. * \endinternal */ void mapCanonicalToTransformed(int num_dimensions, int num_points, TypeOneDRule rule, double x[]) const; /*! * \internal * \brief Apply the inverse map from transformed to canonical points. * * Similar to mapCanonicalToTransformed(), uses the inverse transform. * \endinternal */ template void mapTransformedToCanonical(int num_dimensions, int num_points, TypeOneDRule rule, FloatType x[]) const; /*! * \internal * \brief Returns the quadrature scale factor associated with the linear transform. * * Uses the \b num_dimensions and \b rule, as well as private members \b alpha and \b beta. * \endinternal */ double getQuadratureScale(int num_dimensions, TypeOneDRule rule) const; /*! * \internal * \brief Applies the non-linear transformation to the points. * * Using the set conformal transform (private variables), applies the non-linear transform * to the points \b x with given number of dimensions and number of points. * \endinternal */ void mapConformalCanonicalToTransformed(int num_dimensions, int num_points, double x[]) const; /*! * \internal * \brief Applies the inverse non-linear transformation to the points. * * Using the set conformal transform (private variables), applies the inverse non-linear transform. * \endinternal */ template void mapConformalTransformedToCanonical(int num_dimensions, int num_points, Data2D &x) const; /*! * \internal * \brief Computes the quadrature weight correction for the conformal map. * * Using the set conformal transform (private variables), compute the quadrature weights correction. * \endinternal */ void mapConformalWeights(int num_dimensions, int num_points, double weights[]) const; /*! * \internal * \brief Returns a raw-array with the canonical points, combines both transformations. * * If no transforms have been set, then return an alias to \b x. * Otherwise, \b x_temp is resized, filled with the transformed points and an alias is returned. * Canonical points are given in \b x, and \b num_x holds the number of points. * This method applies both linear and non-linear transforms. * \endinternal */ template const FloatType* formCanonicalPoints(const FloatType *x, Data2D &x_temp, int num_x) const; /*! * \internal * \brief Returns a CUDA raw-array with the canonical points, linear transform only. * * Similar to formCanonicalPoints() except the input and output arrays/vectors are * allocated on the current CUDA device. Works with single and double precision \b T. * \endinternal */ template const T* formCanonicalPointsGPU(const T *gpu_x, int num_x, GpuVector &gpu_x_temp) const; /*! * \internal * \brief Calculates the Jacobian matrix (derivative) of the transform defined by formCanonicalPoints(). Since this matrix is * diagonal, we only return the diagonal vector. * * This is primarily used in the TasmanianSparseGrid::differentiate() method, which applies the chain rule to the (possibly) * transformed grid. */ template std::vector diffCanonicalTransform() const; /*! * \internal * \brief Applies both linear and non-linear transformation to the canonical points. * * The raw-array \b x holds \b num_points and will be overwritten with the result * of the application of both transforms. * \endinternal */ void formTransformedPoints(int num_points, double x[]) const; // when calling get***Points() /*! * \internal * \brief Write the grid to a stream using ASCII format. * * Uses an open stream, writes the grid. * \endinternal */ void writeAscii(std::ostream &ofs) const; /*! * \internal * \brief Read the grid from a stream using ASCII format. * * Uses an open stream, read the grid. * \throws std::runtime_error if Tasmanian detects a problem with the file format. * \endinternal */ void readAscii(std::istream &ifs); /*! * \internal * \brief Write the grid to a stream using binary format. * * Uses an open stream, writes the grid. * \endinternal */ void writeBinary(std::ostream &ofs) const; /*! * \internal * \brief Read the grid from a stream using binary format. * * Uses an open stream, read the grid. * \throws std::runtime_error if Tasmanian detects a problem with the file format. * \endinternal */ void readBinary(std::istream &ifs); #endif // __TASMANIAN_DOXYGEN_SKIP_INTERNAL private: std::unique_ptr acceleration; // must be destroyed last for sycl std::unique_ptr base; std::vector domain_transform_a, domain_transform_b; std::vector conformal_asin_power; std::vector llimits; bool using_dynamic_construction; mutable std::unique_ptr acc_domain; }; /*! * \ingroup TasmanianSG * \brief Returns an empty sparse grid. * * Usage: * \code * auto grid = TasGrid::makeEmpty(); // equivalent to TasGrid::TasmanianSparseGrid grid; * grid = TasGrid::makeEmpty(); // equivalent to grid.clear(); * \endcode * Useful for some MPI calls where some MPI ranks must pass a dummy empty grid. */ inline TasmanianSparseGrid makeEmpty(){ return TasmanianSparseGrid(); } /*! * \ingroup TasmanianSG * \brief Factory method, creates a new grid and calls TasmanianSparseGrid::makeGlobalGrid(). * * Allows for one-line initialization, i.e., * \code * auto grid = TasGrid::makeGlobalGrid(...); * \endcode * as opposed to * \code * TasGrid::TasmanianSparseGrid grid; * grid.makeGlobalGrid(...); * \endcode */ inline TasmanianSparseGrid makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, std::vector const &anisotropic_weights = std::vector(), double alpha = 0.0, double beta = 0.0, const char* custom_filename = nullptr, std::vector const &level_limits = std::vector()){ TasmanianSparseGrid grid; grid.makeGlobalGrid(dimensions, outputs, depth, type, rule, anisotropic_weights, alpha, beta, custom_filename, level_limits); return grid; } /*! * \ingroup TasmanianSG * \brief Factory method, creates a new grid and calls TasmanianSparseGrid::makeSequenceGrid(). * * Allows for one-line initialization, see TasGrid::makeGlobalGrid(). */ inline TasmanianSparseGrid makeSequenceGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, std::vector const &anisotropic_weights = std::vector(), std::vector const &level_limits = std::vector()){ TasmanianSparseGrid grid; grid.makeSequenceGrid(dimensions, outputs, depth, type, rule, anisotropic_weights, level_limits); return grid; } /*! * \ingroup TasmanianSG * \brief Factory method, creates a new grid and calls TasmanianSparseGrid::makeLocalPolynomialGrid(). * * Allows for one-line initialization, see TasGrid::makeGlobalGrid(). */ inline TasmanianSparseGrid makeLocalPolynomialGrid(int dimensions, int outputs, int depth, int order = 1, TypeOneDRule rule = rule_localp, std::vector const &level_limits = std::vector()){ TasmanianSparseGrid grid; grid.makeLocalPolynomialGrid(dimensions, outputs, depth, order, rule, level_limits); return grid; } /*! * \ingroup TasmanianSG * \brief Factory method, creates a new grid and calls TasmanianSparseGrid::makeWaveletGrid(). * * Allows for one-line initialization, see TasGrid::makeGlobalGrid(). */ inline TasmanianSparseGrid makeWaveletGrid(int dimensions, int outputs, int depth, int order = 1, std::vector const &level_limits = std::vector()){ TasmanianSparseGrid grid; grid.makeWaveletGrid(dimensions, outputs, depth, order, level_limits); return grid; } /*! * \ingroup TasmanianSG * \brief Factory method, creates a new grid and calls TasmanianSparseGrid::makeFourierGrid(). * * Allows for one-line initialization, see TasGrid::makeGlobalGrid(). */ inline TasmanianSparseGrid makeFourierGrid(int dimensions, int outputs, int depth, TypeDepth type, std::vector const &anisotropic_weights = std::vector(), std::vector const &level_limits = std::vector()){ TasmanianSparseGrid grid; grid.makeFourierGrid(dimensions, outputs, depth, type, anisotropic_weights, level_limits); return grid; } /*! * \ingroup TasmanianSG * \brief Factory method, creates a new grid and calls TasmanianSparseGrid::read(). * * Allows for one-line initialization, makes a new grid and reads from a file. * \param filename same as TasmanianSparseGrid::read(). * \returns a new grid that is read from the file. */ inline TasmanianSparseGrid readGrid(const char *filename){ TasmanianSparseGrid grid; grid.read(filename); return grid; } /*! * \ingroup TasmanianSG * \brief Overload using std::string. * * Same as readGrid() but the filename is given as a string. */ inline TasmanianSparseGrid readGrid(std::string const &filename){ return readGrid(filename.c_str()); } /*! * \ingroup TasmanianSG * \brief Returns a grid that is a copy of the source. * * Creates a new grid and calls TasmanianSparseGrid::copyGrid() from the source. * \param source is the grid to copy from. * \param outputs_begin same as TasmanianSparseGrid::copyGrid(). * \param outputs_end same as TasmanianSparseGrid::copyGrid(). * * \returns a new grid that is a copy of the source. */ inline TasmanianSparseGrid copyGrid(TasmanianSparseGrid const &source, int outputs_begin = 0, int outputs_end = -1){ TasmanianSparseGrid grid; grid.copyGrid(source, outputs_begin, outputs_end); return grid; } } #endif TASMANIAN-8.1/SparseGrids/TasmanianSparseGridWrapC.cpp000066400000000000000000001004131470551176200224720ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_WRAPC_CPP #define __TASMANIAN_SPARSE_GRID_WRAPC_CPP #include "TasmanianSparseGrid.hpp" // ------------ C Interface for use with Python ctypes and potentially other C codes -------------- // using std::cerr; using std::endl; namespace TasGrid{ extern "C" { void* tsgConstructTasmanianSparseGrid(){ return (void*) new TasmanianSparseGrid(); } void tsgDestructTasmanianSparseGrid(void *grid){ delete ((TasmanianSparseGrid*) grid); } void tsgCopyGrid(void *destination, void *source){ ((TasmanianSparseGrid*) destination)->copyGrid(((TasmanianSparseGrid*) source)); } void tsgCopySubGrid(void *destination, void *source, int outputs_begin, int outputs_end){ ((TasmanianSparseGrid*) destination)->copyGrid(((TasmanianSparseGrid*) source), outputs_begin, outputs_end); } const char* tsgGetVersion(){ return TasmanianSparseGrid::getVersion(); } const char* tsgGetLicense(){ return TasmanianSparseGrid::getLicense(); } int tsgGetVersionMajor(){ return TasmanianSparseGrid::getVersionMajor(); } int tsgGetVersionMinor(){ return TasmanianSparseGrid::getVersionMinor(); } int tsgIsOpenMPEnabled(){ return (TasmanianSparseGrid::isOpenMPEnabled()) ? 1 : 0; } int tsgIsCudaEnabled(){ return (TasmanianSparseGrid::isCudaEnabled()) ? 1 : 0; } int tsgIsHipEnabled(){ return (TasmanianSparseGrid::isHipEnabled()) ? 1 : 0; } int tsgIsDpcppEnabled(){ return (TasmanianSparseGrid::isDpcppEnabled()) ? 1 : 0; } void tsgWrite(void *grid, const char* filename){ ((TasmanianSparseGrid*) grid)->write(filename, mode_ascii); } void tsgWriteBinary(void *grid, const char* filename){ ((TasmanianSparseGrid*) grid)->write(filename, mode_binary); } int tsgRead(void *grid, const char* filename){ try{ ((TasmanianSparseGrid*) grid)->read(filename); return 1; }catch(std::runtime_error &e){ cerr << e.what() << endl; return 0; } } void tsgMakeGlobalGrid(void *grid, int dimensions, int outputs, int depth, const char * sType, const char *sRule, const int *anisotropic_weights, double alpha, double beta, const char* custom_filename, const int *limit_levels){ TypeDepth depth_type = IO::getDepthTypeString(sType); TypeOneDRule rule = IO::getRuleString(sRule); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } if (rule == rule_none){ cerr << "WARNING: incorrect rule type: " << sType << ", defaulting to clenshaw-curtis." << endl; } #endif // NDEBUG ((TasmanianSparseGrid*) grid)->makeGlobalGrid(dimensions, outputs, depth, depth_type, rule, anisotropic_weights, alpha, beta, custom_filename, limit_levels); } void tsgMakeSequenceGrid(void *grid, int dimensions, int outputs, int depth, const char *sType, const char *sRule, const int *anisotropic_weights, const int *limit_levels){ TypeDepth depth_type = IO::getDepthTypeString(sType); TypeOneDRule rule = IO::getRuleString(sRule); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } if (rule == rule_none){ cerr << "WARNING: incorrect rule type: " << sRule << ", defaulting to clenshaw-curtis." << endl; } #endif // NDEBUG if (depth_type == type_none){ depth_type = type_iptotal; } if (rule == rule_none){ rule = rule_clenshawcurtis; } ((TasmanianSparseGrid*) grid)->makeSequenceGrid(dimensions, outputs, depth, depth_type, rule, anisotropic_weights, limit_levels); } void tsgMakeLocalPolynomialGrid(void *grid, int dimensions, int outputs, int depth, int order, const char *sRule, const int *limit_levels){ TypeOneDRule rule = IO::getRuleString(sRule); #ifndef NDEBUG if (rule == rule_none){ cerr << "WARNING: incorrect rule type: " << sRule << ", defaulting to localp." << endl; } #endif // NDEBUG if (rule == rule_none){ rule = rule_localp; } ((TasmanianSparseGrid*) grid)->makeLocalPolynomialGrid(dimensions, outputs, depth, order, rule, limit_levels); } void tsgMakeWaveletGrid(void *grid, int dimensions, int outputs, int depth, int order, const int *limit_levels){ ((TasmanianSparseGrid*) grid)->makeWaveletGrid(dimensions, outputs, depth, order, limit_levels); } void tsgMakeFourierGrid(void *grid, int dimensions, int outputs, int depth, const char *sType, const int *anisotropic_weights, const int *limit_levels){ TypeDepth depth_type = IO::getDepthTypeString(sType); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_level." << endl; } #endif // NDEBUG if (depth_type == type_none){ depth_type = type_level; } ((TasmanianSparseGrid*) grid)->makeFourierGrid(dimensions, outputs, depth, depth_type, anisotropic_weights, limit_levels); } void tsgMakeGridFromCustomTabulated(void *grid, int dimension, int outputs, int depth, const char *sType, void *custom_tabulated, const int *anisotropic_weights, const int *limit_levels) { TypeDepth depth_type = IO::getDepthTypeString(sType); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } #endif // NDEBUG ((TasmanianSparseGrid*) grid)->makeGlobalGrid(dimension, outputs, depth, depth_type, CustomTabulated(*reinterpret_cast(custom_tabulated)), anisotropic_weights, limit_levels); } void tsgUpdateGlobalGrid(void *grid, int depth, const char * sType, const int *anisotropic_weights, const int *limit_levels){ TypeDepth depth_type = IO::getDepthTypeString(sType); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } #endif // NDEBUG if (depth_type == type_none){ depth_type = type_iptotal; } ((TasmanianSparseGrid*) grid)->updateGlobalGrid(depth, depth_type, anisotropic_weights, limit_levels); } void tsgUpdateSequenceGrid(void *grid, int depth, const char * sType, const int *anisotropic_weights, const int *limit_levels){ TypeDepth depth_type = IO::getDepthTypeString(sType); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } #endif // NDEBUG if (depth_type == type_none){ depth_type = type_iptotal; } ((TasmanianSparseGrid*) grid)->updateSequenceGrid(depth, depth_type, anisotropic_weights, limit_levels); } void tsgUpdateFourierGrid(void *grid, int depth, const char * sType, const int *anisotropic_weights, const int *limit_levels){ TypeDepth depth_type = IO::getDepthTypeString(sType); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } #endif // NDEBUG if (depth_type == type_none){ depth_type = type_iptotal; } ((TasmanianSparseGrid*) grid)->updateFourierGrid(depth, depth_type, anisotropic_weights, limit_levels); } double tsgGetAlpha(void *grid){ return ((TasmanianSparseGrid*) grid)->getAlpha(); } double tsgGetBeta(void *grid){ return ((TasmanianSparseGrid*) grid)->getBeta(); } int tsgGetOrder(void *grid){ return ((TasmanianSparseGrid*) grid)->getOrder(); } int tsgGetNumDimensions(void *grid){ return ((TasmanianSparseGrid*) grid)->getNumDimensions(); } int tsgGetNumOutputs(void *grid){ return ((TasmanianSparseGrid*) grid)->getNumOutputs(); } char* tsgGetRule(void *grid){ std::string cppstring = IO::getRuleString( ((TasmanianSparseGrid*) grid)->getRule() ); char *cstring = new char[cppstring.size() + 1]; for(size_t i=0; igetRule() ); size_t max_num = std::min((size_t) buffer_size - 1, cppstring.size()); std::copy_n(cppstring.begin(), max_num, name); name[max_num] = '\0'; *num_actual = (int) max_num; } const char* tsgGetCustomRuleDescription(void *grid){ return ((TasmanianSparseGrid*) grid)->getCustomRuleDescription(); } int tsgGetNumLoaded(void *grid){ return ((TasmanianSparseGrid*) grid)->getNumLoaded(); } int tsgGetNumNeeded(void *grid){ return ((TasmanianSparseGrid*) grid)->getNumNeeded(); } int tsgGetNumPoints(void *grid){ return ((TasmanianSparseGrid*) grid)->getNumPoints(); } void tsgGetLoadedPointsStatic(void *grid, double *x){ return ((TasmanianSparseGrid*) grid)->getLoadedPoints(x); } double* tsgGetLoadedPoints(void *grid){ if (((TasmanianSparseGrid*) grid)->getNumLoaded() == 0){ return 0; } double *x = (double*) malloc(((TasmanianSparseGrid*) grid)->getNumLoaded() * ((TasmanianSparseGrid*) grid)->getNumDimensions() * sizeof(double)); ((TasmanianSparseGrid*) grid)->getLoadedPoints(x); return x; } void tsgGetNeededPointsStatic(void *grid, double *x){ return ((TasmanianSparseGrid*) grid)->getNeededPoints(x); } double* tsgGetNeededPoints(void *grid){ if (((TasmanianSparseGrid*) grid)->getNumNeeded() == 0){ return 0; } double *x = (double*) malloc(((TasmanianSparseGrid*) grid)->getNumNeeded() * ((TasmanianSparseGrid*) grid)->getNumDimensions() * sizeof(double)); ((TasmanianSparseGrid*) grid)->getNeededPoints(x); return x; } void tsgGetPointsStatic(void *grid, double *x){ return ((TasmanianSparseGrid*) grid)->getPoints(x); } double* tsgGetPoints(void *grid){ if (((TasmanianSparseGrid*) grid)->getNumPoints() == 0){ return 0; } double *x = (double*) malloc(((TasmanianSparseGrid*) grid)->getNumPoints() * ((TasmanianSparseGrid*) grid)->getNumDimensions() * sizeof(double)); ((TasmanianSparseGrid*) grid)->getPoints(x); return x; } void tsgGetQuadratureWeightsStatic(void *grid, double *weights){ return ((TasmanianSparseGrid*) grid)->getQuadratureWeights(weights); } double* tsgGetQuadratureWeights(void *grid){ double *w = (double*) malloc(((TasmanianSparseGrid*) grid)->getNumPoints() * sizeof(double)); ((TasmanianSparseGrid*) grid)->getQuadratureWeights(w); return w; } void tsgGetInterpolationWeightsStatic(void *grid, const double *x, double *weights){ ((TasmanianSparseGrid*) grid)->getInterpolationWeights(x, weights); } double* tsgGetInterpolationWeights(void *grid, const double *x){ double *w = (double*) malloc(((TasmanianSparseGrid*) grid)->getNumPoints() * sizeof(double)); ((TasmanianSparseGrid*) grid)->getInterpolationWeights(x, w); return w; } void tsgLoadNeededPoints(void *grid, const double *vals){ ((TasmanianSparseGrid*) grid)->loadNeededPoints(vals); } void tsgLoadNeededValues(void *grid, const double *vals){ ((TasmanianSparseGrid*) grid)->loadNeededValues(vals); } const double* tsgGetLoadedValues(void *grid){ return ((TasmanianSparseGrid*) grid)->getLoadedValues(); } void tsgGetLoadedValuesStatic(void *grid, double *values){ int num_points = ((TasmanianSparseGrid*) grid)->getNumPoints(); int num_outputs = ((TasmanianSparseGrid*) grid)->getNumOutputs(); if ((num_points == 0) || (num_outputs == 0)) return; const double *vals = ((TasmanianSparseGrid*) grid)->getLoadedValues(); std::copy(vals, vals + Utils::size_mult(num_outputs, num_points), values); } void tsgEvaluate(void *grid, const double *x, double *y){ ((TasmanianSparseGrid*) grid)->evaluate(x, y); } void tsgEvaluateFast(void *grid, const double *x, double *y){ ((TasmanianSparseGrid*) grid)->evaluateFast(x, y); } void tsgIntegrate(void *grid, double *q){ ((TasmanianSparseGrid*) grid)->integrate(q); } void tsgDifferentiate(void *grid, const double *x, double *y){ ((TasmanianSparseGrid*) grid)->differentiate(x, y); } void tsgEvaluateBatch(void *grid, const double *x, int num_x, double *y){ ((TasmanianSparseGrid*) grid)->evaluateBatch(x, num_x, y); } void tsgBatchGetInterpolationWeightsStatic(void *grid, const double *x, int num_x, double *weights){ TasmanianSparseGrid* tsg = (TasmanianSparseGrid*) grid; int iNumDim = tsg->getNumDimensions(), iNumPoints = tsg->getNumPoints(); #pragma omp parallel for for(int i=0; igetInterpolationWeights(&(x[i*iNumDim]), &(weights[i*iNumPoints])); } } double* tsgBatchGetInterpolationWeights(void *grid, const double *x, int num_x){ double *weights = (double*) malloc(num_x * ((TasmanianSparseGrid*) grid)->getNumPoints() * sizeof(double)); tsgBatchGetInterpolationWeightsStatic(grid, x, num_x, weights); return weights; } int tsgIsGlobal(void *grid){ return (((TasmanianSparseGrid*) grid)->isGlobal() ? 1 : 0); } int tsgIsSequence(void *grid){ return (((TasmanianSparseGrid*) grid)->isSequence() ? 1 : 0); } int tsgIsLocalPolynomial(void *grid){ return (((TasmanianSparseGrid*) grid)->isLocalPolynomial() ? 1 : 0); } int tsgIsWavelet(void *grid){ return (((TasmanianSparseGrid*) grid)->isWavelet() ? 1 : 0); } int tsgIsFourier(void *grid){ return (((TasmanianSparseGrid*) grid)->isFourier() ? 1 : 0); } void tsgSetDomainTransform(void *grid, const double a[], const double b[]){ ((TasmanianSparseGrid*) grid)->setDomainTransform(a, b); } int tsgIsSetDomainTransfrom(void *grid){ return (((TasmanianSparseGrid*) grid)->isSetDomainTransfrom() ? 1 : 0); } void tsgClearDomainTransform(void *grid){ ((TasmanianSparseGrid*) grid)->clearDomainTransform(); } void tsgGetDomainTransform(void *grid, double a[], double b[]){ ((TasmanianSparseGrid*) grid)->getDomainTransform(a, b); } void tsgSetConformalTransformASIN(void *grid, const int truncation[]){ ((TasmanianSparseGrid*) grid)->setConformalTransformASIN(Utils::copyArray(truncation, ((TasmanianSparseGrid*) grid)->getNumDimensions())); } int tsgIsSetConformalTransformASIN(void *grid){ return (((TasmanianSparseGrid*) grid)->isSetConformalTransformASIN()) ? 1 : 0; } void tsgClearConformalTransform(void *grid){ ((TasmanianSparseGrid*) grid)->clearConformalTransform(); } void tsgGetConformalTransformASIN(void *grid, int truncation[]){ auto truncation_vector = ((TasmanianSparseGrid*) grid)->getConformalTransformASIN(); std::copy(truncation_vector.begin(), truncation_vector.end(), truncation); } void tsgClearLevelLimits(void *grid){ ((TasmanianSparseGrid*) grid)->clearLevelLimits(); } void tsgGetLevelLimits(void *grid, int *limits){ auto llimits = ((TasmanianSparseGrid*) grid)->getLevelLimits(); if (llimits.empty()){ std::fill_n(limits, ((TasmanianSparseGrid*) grid)->getNumDimensions(), -1); }else{ std::copy(llimits.begin(), llimits.end(), limits); } } void tsgSetAnisotropicRefinement(void *grid, const char * sType, int min_growth, int output, const int *level_limits){ TypeDepth depth_type = IO::getDepthTypeString(sType); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } #endif // NDEBUG if (depth_type == type_none){ depth_type = type_iptotal; } ((TasmanianSparseGrid*) grid)->setAnisotropicRefinement(depth_type, min_growth, output, level_limits); } int* tsgEstimateAnisotropicCoefficients(void *grid, const char * sType, int output, int *num_coefficients){ TypeDepth depth_type = IO::getDepthTypeString(sType); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } #endif // NDEBUG if (depth_type == type_none){ depth_type = type_iptotal; } *num_coefficients = ((TasmanianSparseGrid*) grid)->getNumDimensions(); if ((depth_type == type_curved) || (depth_type == type_ipcurved) || (depth_type == type_qpcurved)){ *num_coefficients *= 2; } auto coeff = ((TasmanianSparseGrid*) grid)->estimateAnisotropicCoefficients(depth_type, output); int *result = (int*) malloc((*num_coefficients) * sizeof(int)); for(int i=0; i<*num_coefficients; i++) result[i] = coeff[i]; return result; } void tsgEstimateAnisotropicCoefficientsStatic(void *grid, const char * sType, int output, int *coefficients){ TypeDepth depth_type = IO::getDepthTypeString(sType); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } #endif // NDEBUG if (depth_type == type_none){ depth_type = type_iptotal; } int num_coefficients = ((TasmanianSparseGrid*) grid)->getNumDimensions(); if ((depth_type == type_curved) || (depth_type == type_ipcurved) || (depth_type == type_qpcurved)){ num_coefficients *= 2; } auto coeff = ((TasmanianSparseGrid*) grid)->estimateAnisotropicCoefficients(depth_type, output); for(int i=0; isetSurplusRefinement(tolerance, output, level_limits); } void tsgSetLocalSurplusRefinement(void *grid, double tolerance, const char * sRefinementType, int output, const int *level_limits, const double *scale_correction){ TypeRefinement ref_type = IO::getTypeRefinementString(sRefinementType); #ifndef NDEBUG if (ref_type == refine_none){ cerr << "WARNING: incorrect refinement type: " << sRefinementType << ", defaulting to type_classic." << endl; } #endif // NDEBUG if (ref_type == refine_none){ ref_type = refine_classic; } ((TasmanianSparseGrid*) grid)->setSurplusRefinement(tolerance, ref_type, output, level_limits, scale_correction); } void tsgClearRefinement(void *grid){ ((TasmanianSparseGrid*) grid)->clearRefinement(); } void tsgMergeRefinement(void *grid){ ((TasmanianSparseGrid*) grid)->mergeRefinement(); } void tsgBeginConstruction(void *grid){ ((TasmanianSparseGrid*) grid)->beginConstruction(); } int tsgIsUsingConstruction(void *grid){ return (((TasmanianSparseGrid*) grid)->isUsingConstruction()) ? 1 : 0; } void* tsgGetCandidateConstructionPointsVoidPntr(void *grid, const char *sType, int output, const int *anisotropic_weights, const int *limit_levels){ // internal use only TypeDepth depth_type = IO::getDepthTypeString(sType); #ifndef NDEBUG if (depth_type == type_none){ cerr << "WARNING: incorrect depth type: " << sType << ", defaulting to type_iptotal." << endl; } #endif // NDEBUG if (depth_type == type_none){ depth_type = type_iptotal; } size_t dims = (size_t) ((TasmanianSparseGrid*) grid)->getNumDimensions(); std::vector* vecx = (std::vector*) new std::vector(); std::vector veclimits; if (limit_levels != nullptr) veclimits = std::vector(limit_levels, limit_levels + dims); if (anisotropic_weights == nullptr){ *vecx = ((TasmanianSparseGrid*) grid)->getCandidateConstructionPoints(depth_type, output, veclimits); }else{ std::vector vecweights(anisotropic_weights, anisotropic_weights + (((depth_type == type_curved) || (depth_type == type_ipcurved) || (depth_type == type_qpcurved)) ? 2*dims : dims)); *vecx = ((TasmanianSparseGrid*) grid)->getCandidateConstructionPoints(depth_type, vecweights, veclimits); } return (void*) vecx; } void* tsgGetCandidateConstructionPointsSurplusVoidPntr(void *grid, double tolerance, const char *sRefType, int output, const int *limit_levels, const double *scale_correction){ // internal use only TypeRefinement ref_type = IO::getTypeRefinementString(sRefType); #ifndef NDEBUG if (ref_type == refine_none){ cerr << "WARNING: incorrect depth type: " << sRefType << ", defaulting to refine_classic." << endl; } #endif // NDEBUG if (ref_type == refine_none){ ref_type = refine_classic; } size_t dims = (size_t) ((TasmanianSparseGrid*) grid)->getNumDimensions(); std::vector* vecx = (std::vector*) new std::vector(); std::vector veclimits; if (limit_levels != nullptr) veclimits = std::vector(limit_levels, limit_levels + dims); std::vector vecscale; if (scale_correction != nullptr){ size_t active_outputs = (size_t) (output == -1) ? ((TasmanianSparseGrid*) grid)->getNumOutputs() : 1; vecscale = std::vector(scale_correction, scale_correction + ((size_t) ((TasmanianSparseGrid*) grid)->getNumLoaded() * active_outputs)); } *vecx = ((TasmanianSparseGrid*) grid)->getCandidateConstructionPoints(tolerance, ref_type, output, veclimits, vecscale); return (void*) vecx; } void tsgGetCandidateConstructionPoints(void *grid, const char *sType, int output, const int *anisotropic_weights, const int *limit_levels, int *num_points, double **x){ size_t dims = (size_t) ((TasmanianSparseGrid*) grid)->getNumDimensions(); std::vector* vecx = (std::vector*) tsgGetCandidateConstructionPointsVoidPntr(grid, sType, output, anisotropic_weights, limit_levels); *num_points = (int)(vecx->size() / dims); *x = (double*) malloc(vecx->size() * sizeof(double)); std::copy_n(vecx->data(), vecx->size(), *x); delete vecx; } void tsgGetCandidateConstructionSurplusPoints(void *grid, double tolerance, const char *sRefType, int output, const int *limit_levels, const double *scale_correction, int *num_points, double **x){ size_t dims = (size_t) ((TasmanianSparseGrid*) grid)->getNumDimensions(); std::vector* vecx = (std::vector*) tsgGetCandidateConstructionPointsSurplusVoidPntr(grid, tolerance, sRefType, output, limit_levels, scale_correction); *num_points = (int)(vecx->size() / dims); *x = (double*) malloc(vecx->size() * sizeof(double)); std::copy_n(vecx->data(), vecx->size(), *x); delete vecx; } int tsgGetCandidateConstructionPointsPythonGetNP(void *grid, const void *vecx){ return (int) (((std::vector*) vecx)->size() / ((size_t) ((TasmanianSparseGrid*) grid)->getNumDimensions())); } void tsgGetCandidateConstructionPointsPythonStatic(const void *vecx, double *x){ std::copy_n(((std::vector*) vecx)->data(), ((std::vector*) vecx)->size(), x); } void tsgGetCandidateConstructionPointsPythonDeleteVect(void *vecx){ delete ((std::vector*) vecx); } void tsgLoadConstructedPoint(void *grid, const double *x, int numx, const double *y){ ((TasmanianSparseGrid*) grid)->loadConstructedPoints(x, numx, y); } void tsgFinishConstruction(void *grid){ ((TasmanianSparseGrid*) grid)->finishConstruction(); } void tsgRemovePointsByHierarchicalCoefficient(void *grid, double tolerance, int output, const double *scale_correction){ ((TasmanianSparseGrid*) grid)->removePointsByHierarchicalCoefficient(tolerance, output, scale_correction); } void tsgRemovePointsByHierarchicalCoefficientHardCutoff(void *grid, int num_new, int output, const double *scale_correction){ ((TasmanianSparseGrid*) grid)->removePointsByHierarchicalCoefficient(num_new, output, scale_correction); } void tsgEvaluateHierarchicalFunctions(void *grid, const double *x, int num_x, double *y){ ((TasmanianSparseGrid*) grid)->evaluateHierarchicalFunctions(x, num_x, y); } void tsgEvaluateSparseHierarchicalFunctions(void *grid, const double x[], int num_x, int **pntr, int **indx, double **vals){ int num_nz = ((TasmanianSparseGrid*) grid)->evaluateSparseHierarchicalFunctionsGetNZ(x, num_x); *pntr = (int*) malloc((num_x+1) * sizeof(int)); *indx = (int*) malloc(num_nz * sizeof(int)); *vals = (double*) malloc(num_nz * sizeof(double)); ((TasmanianSparseGrid*) grid)->evaluateSparseHierarchicalFunctionsStatic(x, num_x, *pntr, *indx, *vals); } int tsgEvaluateSparseHierarchicalFunctionsGetNZ(void *grid, const double x[], int num_x){ return ((TasmanianSparseGrid*) grid)->evaluateSparseHierarchicalFunctionsGetNZ(x, num_x); } void tsgEvaluateSparseHierarchicalFunctionsStatic(void *grid, const double x[], int num_x, int *pntr, int *indx, double *vals){ ((TasmanianSparseGrid*) grid)->evaluateSparseHierarchicalFunctionsStatic(x, num_x, pntr, indx, vals); } void tsgGetHierarchicalSupportStatic(void *grid, double support[]){ std::vector sup = ((TasmanianSparseGrid*) grid)->getHierarchicalSupport(); std::copy(sup.begin(), sup.end(), support); } const double* tsgGetHierarchicalCoefficients(void *grid){ return ((TasmanianSparseGrid*) grid)->getHierarchicalCoefficients(); } void tsgGetHierarchicalCoefficientsStatic(void *grid, double *coeff){ ((TasmanianSparseGrid*) grid)->getHierarchicalCoefficientsStatic(coeff); } void tsgSetHierarchicalCoefficients(void *grid, const double *c){ ((TasmanianSparseGrid*) grid)->setHierarchicalCoefficients(c); } double* tsgIntegrateHierarchicalFunctions(void *grid){ double *x = (double*) malloc(((TasmanianSparseGrid*) grid)->getNumPoints() * sizeof(double)); ((TasmanianSparseGrid*) grid)->integrateHierarchicalFunctions(x); return x; } void tsgIntegrateHierarchicalFunctionsStatic(void *grid, double *integrals){ ((TasmanianSparseGrid*) grid)->integrateHierarchicalFunctions(integrals); } // to be called from Python only, must later call delete[] on the pointer int* tsgPythonGetGlobalPolynomialSpace(void *grid, int interpolation, int *num_indexes){ std::vector space = ((TasmanianSparseGrid*) grid)->getGlobalPolynomialSpace((interpolation != 0)); int *indx = new int[space.size()]; std::copy(space.begin(), space.end(), indx); *num_indexes = (int) space.size() / ((TasmanianSparseGrid*) grid)->getNumDimensions(); return indx; } // to be used in C, creates a C pointer (requires internal copy of data) void tsgGetGlobalPolynomialSpace(void *grid, int interpolation, int *num_indexes, int **indexes){ std::vector space = ((TasmanianSparseGrid*) grid)->getGlobalPolynomialSpace((interpolation != 0)); *num_indexes = (int) space.size() / ((TasmanianSparseGrid*) grid)->getNumDimensions(); if (!space.empty()){ *indexes = (int*) malloc(space.size() * sizeof(int)); std::copy(space.begin(), space.end(), *indexes); } } void tsgPrintStats(void *grid){ ((TasmanianSparseGrid*) grid)->printStats(); } void tsgEnableAcceleration(void *grid, const char *accel){ ((TasmanianSparseGrid*) grid)->enableAcceleration(AccelerationMeta::getIOAccelerationString(accel)); } void tsgEnableAccelerationGPU(void *grid, const char *accel, int gpu){ ((TasmanianSparseGrid*) grid)->enableAcceleration(AccelerationMeta::getIOAccelerationString(accel), gpu); } //int tsgGetAccelerationTypeInt(void *grid){ return AccelerationMeta::getIOAccelerationInt(((TasmanianSparseGrid*) grid)->getAccelerationType()); } // int to acceleration type const char* tsgGetAccelerationType(void *grid){ return AccelerationMeta::getIOAccelerationString(((TasmanianSparseGrid*) grid)->getAccelerationType()); } void tsgSetGPUID(void *grid, int gpuID){ ((TasmanianSparseGrid*) grid)->setGPUID(gpuID); } int tsgGetGPUID(void *grid){ return ((TasmanianSparseGrid*) grid)->getGPUID(); } int tsgGetNumGPUs(){ return TasmanianSparseGrid::getNumGPUs(); } int tsgGetGPUMemory(int gpu){ return TasmanianSparseGrid::getGPUMemory(gpu); } int tsgIsAccelerationAvailable(const char *accel){ return (TasmanianSparseGrid::isAccelerationAvailable(AccelerationMeta::getIOAccelerationString(accel))) ? 1 : 0; } void tsgGetGPUName(int gpu, int num_buffer, char *buffer, int *num_actual){ // gpu is the gpuID, num_buffer is the size of *buffer, num_actual returns the actual number of chars if (num_buffer == 0) return; std::string name = TasmanianSparseGrid::getGPUName(gpu); size_t chars = std::min((size_t) (num_buffer - 1), name.size()); std::copy(name.begin(), name.begin() + chars, buffer); buffer[chars] = '\0'; *num_actual = (int) chars; } void tsgDeleteInts(int *p){ delete[] p; } void* tsgConstructCustomTabulated(){ return (void*) new CustomTabulated(); } void tsgDestructCustomTabulated(void* ct){ delete ((CustomTabulated*) ct); } void tsgWriteCustomTabulated(void *ct, const char* filename){ std::ofstream ofs(filename, std::ios::out); if (!ofs.good()) std::cerr << "ERROR: must provide valid filename!" << std::endl; ((CustomTabulated*) ct)->write(ofs); // false == mode_ascii } int tsgReadCustomTabulated(void *ct, const char* filename){ try{ ((CustomTabulated*) ct)->read(filename); return 1; }catch(std::runtime_error &e){ cerr << e.what() << endl; return 0; }catch(std::invalid_argument &e){ cerr << e.what() << endl; return 0; } } int tsgGetNumLevelsCustomTabulated(void* ct){ return ((CustomTabulated*) ct)->getNumLevels(); } int tsgGetNumPointsCustomTabulated(void* ct, const int level){ return ((CustomTabulated*) ct)->getNumPoints(level); } int tsgGetIExactCustomTabulated(void* ct, const int level){ return ((CustomTabulated*) ct)->getIExact(level); } int tsgGetQExactCustomTabulated(void* ct, const int level){ return ((CustomTabulated*) ct)->getQExact(level); } const char* tsgGetDescriptionCustomTabulated(void* ct) { return ((CustomTabulated*) ct)->getDescription(); } void tsgGetWeightsNodesStaticCustomTabulated(void* ct, int level, double* w, double* x) {((CustomTabulated*) ct)->getWeightsNodes(level, w, x); } // Note: cnodes and cweights are passed as 1D arrays, but represent a list of vectors. void* tsgMakeCustomTabulatedFromData(const int cnum_levels, const int* cnum_nodes, const int* cprecision, const double* cnodes, const double* cweights, char* cdescription) { std::vector> vec_cnodes(cnum_levels), vec_cweights(cnum_levels); int ptr_idx = 0; for (int l=0; l(&cnodes[ptr_idx], &cnodes[ptr_idx] + cnum_nodes[l]); vec_cweights[l] = std::vector(&cweights[ptr_idx], &cweights[ptr_idx] + cnum_nodes[l]); ptr_idx += cnum_nodes[l]; } return new TasGrid::CustomTabulated(std::vector(cnum_nodes, cnum_nodes + cnum_levels), std::vector(cprecision, cprecision + cnum_levels), std::move(vec_cnodes), std::move(vec_cweights), cdescription); } void* tsgGetSubrules(void* ct, const int start_index, const int stride, char* description) { CustomTabulated *sub_ct = new CustomTabulated; *sub_ct = getSubrules(*reinterpret_cast(ct), start_index, stride, description); return (void*) sub_ct; } } } #endif TASMANIAN-8.1/SparseGrids/gridtestCLICommon.hpp000066400000000000000000000132121470551176200211710ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASGRID_COMMON_HPP #define __TASGRID_COMMON_HPP /*! * \internal * \file gridtestCLICommon.hpp * \brief Common executable includes and templates. * \author Miroslav Stoyanov * \ingroup TasmanianCLI * * Defines common includes for the various executables and templates for managing command line arguments. * \endinternal */ #include #include #include #include "TasmanianSparseGrid.hpp" using std::cout; using std::cerr; using std::endl; using std::setw; using namespace TasGrid; /*! * \internal * \ingroup TasmanianCLI * \brief Creates a std::deque of strings from the CLI arguments, skips the first argument. * * Converts the CLI arguments to strings, the first argument is the name of the executable and it is omitted. * \endinternal */ inline std::deque stringArgs(int argc, const char** argv){ std::deque args; for(int i = 1; i < argc; i++) args.push_back(std::string(argv[i])); return args; } /*! * \internal * \ingroup TasmanianCLI * \brief Returns \b true if the string contains a sub-string with the word "help" (case insensitive). * * \endinternal */ inline bool hasHelp(std::string const &arg){ std::string lower(arg.size(), ' '); std::transform(arg.begin(), arg.end(), lower.begin(), [](char c)->char{ return static_cast(std::tolower(static_cast(c))); }); auto pos = lower.find("help"); if ((pos < lower.size()) && (pos + 4 <= lower.size())) return (lower.substr(pos, pos + 4).compare("help") == 0); return false; } /*! * \internal * \ingroup TasmanianCLI * \brief Returns \b true if the string contains a request for version information. * * Accepted strings are "-v", "version", "verbose", and "info" with "-" or "--". * \endinternal */ inline bool hasInfo(std::string const &s){ std::map accpetable = { {"-v", true}, {"version", true}, {"-version", true}, {"--version", true}, {"verbose", true}, {"-verbose", true}, {"--verbose", true}, {"info", true}, {"-info", true}, {"--info", true}, }; try{ return accpetable.at(s); }catch(std::out_of_range &){ return false; } } /*! * \internal * \ingroup TasmanianCLI * \brief Returns \b true if the string contains "random", "-random", "rand", or "-rand" * * \endinternal */ inline bool hasRandom(std::string const &s){ return ((s == "random") || (s == "-random") || (s == "rand") || (s == "-rand")); } /*! * \internal * \ingroup TasmanianCLI * \brief Returns \b true if the string contains "gpu", "-gpu", "gpuid", or "-gpuid" * * \endinternal */ inline bool hasGpuID(std::string const &s){ return ((s == "gpu") or (s == "-gpu") or (s == "gpuid") or (s == "-gpuid")); } /*! * \ingroup TasmanianCLI * \brief Returns the specified GPU id (could be -1) or throws */ inline int getGpuID(std::deque const &args){ int gpuid = (args.empty()) ? -2 : std::stoi(args.front()); if ((gpuid < -1) || (gpuid >= TasmanianSparseGrid::getNumGPUs())){ cerr << "ERROR: -gpuid requires a valid gpuid!" << endl; cerr << " see ./tasgrid -v for a list of detected GPUs." << endl; throw std::invalid_argument("Invalid GPU ID!"); } return gpuid; } #endif TASMANIAN-8.1/SparseGrids/gridtestExternalTests.cpp000066400000000000000000003762251470551176200222310ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASGRID_TESTER_CPP #define __TASGRID_TESTER_CPP #include "gridtestExternalTests.hpp" #include "gridtestTestHelpers.hpp" std::minstd_rand park_miller(10); std::vector genRandom(int num_samples, std::vector const &lower, std::vector const &upper){ if (lower.size() != upper.size()) throw std::runtime_error("Lower/Upper dimension mismatch in genRandom()"); std::vector x(Utils::size_mult(num_samples, lower.size())); Utils::Wrapper2D wrapp((int) lower.size(), x.data()); for(int i=0; i(lower[j], upper[j])(park_miller); } } return x; } std::vector genRandom(int num_samples, int num_dimensions = 1){ std::vector x(Utils::size_mult(num_samples, num_dimensions)); std::uniform_real_distribution unif(-1.0, 1.0); for(auto &v : x) v = unif(park_miller); return x; } double unitDerivativeTests(const BaseFunction *f, TasmanianSparseGrid &grid) { // Test the differentiate method on some common 1D nodes (in the 1st dimension) and return the max relative error. std::vector unique_nodes; if (grid.getRule() == TasGrid::rule_localp0) // Avoid boundary points as not all functions have value zero on these points. unique_nodes = {0.0, -0.5, 0.5, -0.5773502691896257, 0.5773502691896257}; else unique_nodes = {0.0, -1.0, 1.0, -0.5, 0.5, -0.5773502691896257, 0.5773502691896257}; int num_dimensions = f->getNumInputs(); int num_outputs = f->getNumOutputs(); std::vector points(Utils::size_mult(num_dimensions, unique_nodes.size()), 0.0); for (size_t i=0; i r(num_entries), y(num_entries); double rel_err = 0.0; for (size_t k=0; kgetDerivative(&(points[Utils::size_mult(k, num_dimensions)]), r.data()); grid.differentiate(&(points[Utils::size_mult(k, num_dimensions)]), y.data()); double nrm = 0.0; double err = 0.0; for (int i=0; i 0){ Data2D points(grid.getNumDimensions(), num_needed, grid.getNeededPoints()); Data2D values(grid.getNumOutputs(), num_needed); for(int i=0; ieval(points.getStrip(i), values.getStrip(i)); grid.loadNeededPoints(values.data()); } } template void assert_copy_move(){ static_assert(std::is_copy_constructible::value, "lost the copy constructor"); static_assert(std::is_move_constructible::value, "lost the move constructor"); static_assert(std::is_copy_assignable::value, "lost the copy ="); static_assert(std::is_move_assignable::value, "lost the move ="); } template void assert_move_not_copy(){ static_assert(!std::is_copy_constructible::value, "got a leaking copy constructor"); static_assert(std::is_move_constructible::value, "lost the move constructor"); static_assert(!std::is_copy_assignable::value, "got a leaking bad copy ="); static_assert(std::is_move_assignable::value, "lost the move ="); } void static_assertions(){ // does nothing but a bunch of static asserts assert_copy_move(); assert_copy_move(); assert_copy_move(); assert_copy_move>(); assert_copy_move>(); assert_copy_move(); assert_copy_move(); assert_copy_move(); assert_move_not_copy(); assert_copy_move(); assert_copy_move(); assert_move_not_copy>(); assert_move_not_copy(); assert_move_not_copy(); } ExternalTester::ExternalTester(int in_num_mc) : num_mc(in_num_mc), verbose(false), gpuid(-1) { for(auto acc : std::vector{accel_none, accel_cpu_blas, accel_gpu_cublas, accel_gpu_cuda, accel_gpu_magma}){ if (AccelerationMeta::isAvailable(acc)) available_acc.push_back(acc); } #ifdef Tasmanian_ENABLE_DPCPP test_queue.init_testing(gpuid); #endif // Hardcoded test types. quad_only = {type_integration}; int_only = {type_nodal_interpolation, type_internal_interpolation}; diff_only = {type_nodal_differentiation, type_internal_differentiation}; quad_int.reserve(quad_only.size() + int_only.size()); std::copy(quad_only.begin(), quad_only.end(), std::back_inserter(quad_int)); std::copy(int_only.begin(), int_only.end(), std::back_inserter(quad_int)); quad_diff.reserve(quad_only.size() + diff_only.size()); std::copy(quad_only.begin(), quad_only.end(), std::back_inserter(quad_diff)); std::copy(diff_only.begin(), diff_only.end(), std::back_inserter(quad_diff)); int_diff.reserve(int_only.size() + diff_only.size()); std::copy(int_only.begin(), int_only.end(), std::back_inserter(int_diff)); std::copy(diff_only.begin(), diff_only.end(), std::back_inserter(int_diff)); all_test_types.reserve(quad_only.size() + int_only.size() + diff_only.size()); std::copy(quad_only.begin(), quad_only.end(), std::back_inserter(all_test_types)); std::copy(int_only.begin(), int_only.end(), std::back_inserter(all_test_types)); std::copy(diff_only.begin(), diff_only.end(), std::back_inserter(all_test_types)); } ExternalTester::~ExternalTester(){} void ExternalTester::resetRandomSeed(){ park_miller.seed(static_cast(std::time(nullptr))); } void ExternalTester::setVerbose(bool new_verbose){ verbose = new_verbose; } void ExternalTester::setGPUID(int gpu_id){ gpuid = gpu_id; #ifdef Tasmanian_ENABLE_DPCPP test_queue.init_testing(gpuid); #endif } const char* ExternalTester::findGaussPattersonTable(){ // TasmanianGPTableBuild and TasmanianGPTableInstall are defined in tasgridLogs.hpp (configured from CMake) if (std::ifstream(TasmanianGPTableBuild).good()) return TasmanianGPTableBuild; if (std::ifstream(TasmanianGPTableInstall).good()) return TasmanianGPTableInstall; throw std::runtime_error("Cannot open custom file GaussPattersonRule.table in any of the expected locations in the build or install folders!"); return nullptr; } const char* ExternalTester::testName(TestType type){ if (type == type_integration) return "integration test"; else if (type == type_nodal_interpolation) return "w-interpolation"; else if (type == type_nodal_differentiation) return "w-differentiation"; else if (type == type_internal_interpolation) return "interpolation"; else if (type == type_internal_differentiation) return "differentiation"; else return "unknown test"; } TestList ExternalTester::hasTest(std::string const &s){ std::map string_to_test = { {"all", test_all}, {"acceleration", test_acceleration}, {"domain", test_domain}, {"refinement", test_refinement}, {"global", test_global}, {"local", test_local}, {"wavelet", test_wavelet}, {"fourier", test_fourier}, }; try{ return string_to_test.at(s); }catch(std::out_of_range &){ return test_none; } } bool ExternalTester::Test(TestList test) const{ cout << endl << endl; cout << "---------------------------------------------------------------------" << endl; cout << " Tasmanian Sparse Grids Module: Functionality Test" << endl; cout << "---------------------------------------------------------------------" << endl << endl; bool passAccel = true; bool passDomain = true; bool passRefine = true; bool passGlobal = true; bool passLocal = true; bool passWavelet = true; bool passFourier = true; if ((test == test_all) || (test == test_acceleration)) passAccel = testAllAcceleration(); if ((test == test_all) || (test == test_domain)) passDomain = testAllDomain(); if ((test == test_all) || (test == test_refinement)) passRefine = testAllRefinement(); if ((test == test_all) || (test == test_global)) passGlobal = testAllGlobal(); if ((test == test_all) || (test == test_local)) passLocal = testAllPWLocal(); if ((test == test_all) || (test == test_wavelet)) passWavelet = testAllWavelet(); if ((test == test_all) || (test == test_fourier)) passFourier = testAllFourier(); bool pass = passGlobal && passLocal && passWavelet && passFourier && passRefine && passDomain && passAccel; //bool pass = true; cout << endl; if (pass){ cout << "---------------------------------------------------------------------" << endl; cout << " All Tests Completed Successfully" << endl; cout << "---------------------------------------------------------------------" << endl << endl; }else{ cout << "FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL" << endl; cout << " Some Tests Have Failed" << endl; cout << "FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL" << endl << endl; } return pass; } TestResults ExternalTester::getError(const BaseFunction *f, TasGrid::TasmanianSparseGrid &grid, TestType type, std::vector const &x) const{ TestResults R; int num_dimensions = f->getNumInputs(); int num_outputs = f->getNumOutputs(); int num_points = grid.getNumPoints(); if (type == type_integration or type == type_nodal_interpolation or type == type_nodal_differentiation){ int num_entries = (type == type_nodal_differentiation) ? num_dimensions * num_outputs : num_outputs; auto points = grid.getPoints(); std::vector weights; if (type == type_integration) weights = grid.getQuadratureWeights(); else if (type == type_nodal_interpolation) weights = grid.getInterpolationWeights(x); else weights = grid.getDifferentiationWeights(x); // Sequential version std::vector y(num_entries); std::vector r(num_entries, 0.0); if (type == type_nodal_differentiation){ for(int i=0; ieval(&(points[i*num_dimensions]), y.data()); for (int k=0; keval(&(points[i*num_dimensions]), y.data()); for(int k=0; kgetIntegral(y.data()); }else if (type == type_nodal_differentiation){ f->getDerivative(x.data(), y.data()); }else{ f->eval(x.data(), y.data()); } for(int j=0; j test_x = genRandom(num_mc, num_dimensions); int num_entries = (type == type_internal_interpolation) ? num_outputs : num_outputs * num_dimensions; std::vector result_tasm(num_mc * num_entries); std::vector result_true(num_mc * num_entries); if (type == type_internal_interpolation) { #pragma omp parallel for // note that iterators do not work with OpenMP, direct indexing does for(int i=0; ieval(&(test_x[i * num_dimensions]), &(result_true[i * num_entries])); } } else { #pragma omp parallel for // note that iterators do not work with OpenMP, direct indexing does for(int i=0; igetDerivative(&(test_x[i * num_dimensions]), &(result_true[i * num_entries])); } } double rel_err = 0.0; // relative error for(int k=0; k &tests, const int depths[], const double tols[]) const{ TasGrid::TasmanianSparseGrid grid; TestResults R; size_t num_global_tests = tests.size(); TasGrid::TypeDepth type = (rule == rule_fourier ? TasGrid::type_level : TasGrid::type_iptotal); std::vector x = genRandom(f->getNumInputs()); if (rule == rule_fourier){ for(int i=0; igetNumInputs(); i++) x[i] = 0.5*(x[i]+1.0); } // map to canonical [0,1]^d bool bPass = true; const char *custom_filename = (rule == rule_customtabulated) ? findGaussPattersonTable() : 0; int num_fn_outputs = (tests == quad_only) ? 0 : f->getNumOutputs(); for(size_t i=0; igetNumInputs(), num_fn_outputs, depths[i], type); }else{ grid.makeFourierGrid(f->getNumInputs(), num_fn_outputs, depths[i], type, anisotropic); } grid.setDomainTransform(std::vector(grid.getNumDimensions(), -1.0), std::vector(grid.getNumDimensions(), 1.0)); }else{ if (anisotropic == nullptr){ grid = makeGlobalGrid(f->getNumInputs(), num_fn_outputs, depths[i], type, rule, std::vector(), alpha, beta, custom_filename); }else{ grid.makeGlobalGrid(f->getNumInputs(), num_fn_outputs, depths[i], type, rule, anisotropic, alpha, beta, custom_filename); } } R = getError(f, grid, tests[i], x); if (R.error > tols[i]){ bPass = false; cout << setw(18) << "ERROR: FAILED " << (rule == rule_fourier ? "fourier" : "global") << setw(25) << IO::getRuleString(rule); cout << setw(25) << testName(tests[i]) << " failed function: " << f->getDescription(); cout << setw(10) << " observed: " << R.error << " expected: " << tols[i] << endl; } } if (rule == rule_customtabulated){ TasGrid::TasmanianSparseGrid grid_copy; for(size_t i=0; i<2*num_global_tests; i++){ if (i < num_global_tests){ grid.makeGlobalGrid(f->getNumInputs(), num_fn_outputs, depths[i], type, rule, anisotropic, alpha, beta, custom_filename); }else{ CustomTabulated custom; custom.read(custom_filename); grid = TasmanianSparseGrid(); grid.makeGlobalGrid(f->getNumInputs(), num_fn_outputs, depths[i % num_global_tests], type, std::move(custom), anisotropic); } grid_copy = grid; R = getError(f, grid_copy, tests[i % num_global_tests], x); if (R.error > tols[i % num_global_tests]){ bPass = false; cout << setw(18) << "ERROR: FAILED global" << setw(25) << IO::getRuleString(rule); cout << setw(25) << testName(tests[i % num_global_tests]) << " failed function: " << f->getDescription(); cout << setw(10) << "observed: " << R.error << " expected: " << tols[i % num_global_tests] << endl; } } } if (TasGrid::OneDimensionalMeta::isSequence(rule)){ for(size_t i=0; igetNumInputs(), 0, depths[i], type, rule, anisotropic); R = getError(f, grid, type_integration); }else{ grid = makeSequenceGrid(f->getNumInputs(), f->getNumOutputs(), depths[i], type, rule, (anisotropic != nullptr) ? std::vector(anisotropic, anisotropic + f->getNumInputs()) : std::vector()); R = getError(f, grid, tests[i], x); } if (R.error > tols[i]){ bPass = false; cout << setw(18) << "ERROR: FAILED sequence" << setw(25) << IO::getRuleString(rule); cout << setw(25) << testName(tests[i]) << " failed function: " << f->getDescription(); cout << setw(10) << " observed: " << R.error << " expected: " << tols[i] << endl; } } } return bPass; } bool ExternalTester::performGlobalTest(TasGrid::TypeOneDRule rule) const{ double alpha = 0.3, beta = 0.7; bool pass = true; int wfirst = 10, wsecond = 35, wthird = 15; if (rule == TasGrid::rule_clenshawcurtis){ { TasGrid::TypeOneDRule oned = TasGrid::rule_clenshawcurtis; const int depths1[5] = { 25, 25, 25, 25, 25 }; const double tols1[5] = { 1.E-12, 1.E-12, 1.E-11, 1.E-09, 1.E-09 }; const int depths2[5] = { 25, 27, 27, 27, 27 }; const double tols2[5] = { 1.E-12, 1.E-10, 1.E-11, 1.E-09, 1.E-09 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if (rule == TasGrid::rule_clenshawcurtis0){ { TasGrid::TypeOneDRule oned = TasGrid::rule_clenshawcurtis0; const int depths1[5] = { 25, 25, 25, 25, 25 }; const double tols1[5] = { 1.E-12, 1.E-12, 1.E-11, 1.E-10, 1.E-10 }; if (testGlobalRule(&f21sinsin, oned, 0, alpha, beta, all_test_types, depths1, tols1)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_chebyshev) || (rule == TasGrid::rule_chebyshevodd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[5] = { 22, 22, 22, 22, 22 }; const double tols1[5] = { 1.E-12, 1.E-10, 1.E-10, 1.E-08, 1.E-08 }; const int depths2[5] = { 22, 22, 22, 22, 22 }; const double tols2[5] = { 1.E-12, 1.E-09, 1.E-09, 1.E-08, 1.E-08 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_leja) || (rule == TasGrid::rule_lejaodd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 3.E-10, 5.E-09, 5.E-09, 5.E-07, 5.E-07 }; const int depths2[5] = { 20, 20, 20, 20, 20 }; const double tols2[5] = { 3.E-09, 5.E-08, 5.E-08, 5.E-06, 5.E-06 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if (rule == TasGrid::rule_rleja){ { TasGrid::TypeOneDRule oned = TasGrid::rule_rleja; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 3.E-10, 1.E-08, 1.E-08, 1.E-07, 1.E-07 }; const int depths2[5] = { 20, 20, 20, 20, 20 }; const double tols2[5] = { 3.E-09, 5.E-08, 5.E-08, 5.E-06, 5.E-06 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_rlejadouble2) || (rule == TasGrid::rule_rlejadouble4)){ { TasGrid::TypeOneDRule oned = TasGrid::rule_rlejadouble2; const int depths1[5] = { 25, 25, 25, 25, 25 }; const double tols1[5] = { 1.E-12, 1.E-11, 1.E-11, 1.E-08, 1.E-08 }; const int depths2[5] = { 25, 27, 27, 27, 27 }; const double tols2[5] = { 1.E-12, 1.E-10, 1.E-10, 1.E-08, 1.E-08 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if (rule == TasGrid::rule_rlejaodd){ { TasGrid::TypeOneDRule oned = TasGrid::rule_rlejaodd; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 3.E-10, 5.E-09, 5.E-09, 5.E-08, 5.E-08 }; const int depths2[5] = { 20, 20, 20, 20, 20 }; const double tols2[5] = { 3.E-09, 5.E-08, 5.E-08, 5.E-07, 5.E-07 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if (rule == TasGrid::rule_rlejashifted){ { TasGrid::TypeOneDRule oned = TasGrid::rule_rlejashifted; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 3.E-10, 1.E-08, 1.E-08, 1.E-07, 1.E-07 }; const int depths2[5] = { 20, 20, 20, 20, 20 }; const double tols2[5] = { 3.E-09, 5.E-08, 5.E-08, 5.E-07, 5.E-07 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if (rule == TasGrid::rule_rlejashiftedeven){ { TasGrid::TypeOneDRule oned = TasGrid::rule_rlejashiftedeven; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 3.E-10, 5.E-09, 5.E-09, 5.E-08, 5.E-08 }; const int depths2[5] = { 20, 20, 20, 20, 20 }; const double tols2[5] = { 6.E-09, 5.E-08, 5.E-08, 5.E-07, 5.E-07 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if (rule == TasGrid::rule_rlejashifteddouble){ { TasGrid::TypeOneDRule oned = TasGrid::rule_rlejashifteddouble; const int depths1[5] = { 25, 25, 25, 25, 25 }; const double tols1[5] = { 1.E-12, 1.E-12, 1.E-11, 1.E-08, 1.E-08 }; const int depths2[5] = { 25, 27, 27, 27, 27 }; const double tols2[5] = { 1.E-12, 1.E-10, 1.E-11, 1.E-08, 1.E-08 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_mindelta) || (rule == TasGrid::rule_mindeltaodd) || (rule == TasGrid::rule_minlebesgue) || (rule == TasGrid::rule_minlebesgueodd) || (rule == TasGrid::rule_maxlebesgue) || (rule == TasGrid::rule_maxlebesgueodd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 3.E-10, 5.E-09, 5.E-09, 5.E-07, 5.E-07 }; const int depths2[5] = { 20, 20, 20, 20, 20 }; const double tols2[5] = { 3.E-09, 5.E-08, 5.E-08, 5.E-07, 5.E-07 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} #ifndef __FAST_MATH__ // test the hard-coded sequence values vs the optimizer // computing the sequence point is ill-conditioned problem and breaks down when --fast-math is enabled // disable the test, fast maths should only use the hard-coded series if (rule == rule_minlebesgue){ int n = 22; auto minleb = Optimizer::getGreedyNodes(n); auto precomputed = Optimizer::getPrecomputedMinLebesgueNodes(); double R = Optimizer::getNextNode(minleb); if (std::abs(R - precomputed[n]) > 1.E-8){ pass = false; cout << "ERROR: mismatch in stored vs computed nodes for rule_minlebesgue rule" << endl; } }else if (rule == rule_mindelta){ int n = 22; auto mindel = Optimizer::getGreedyNodes(n); auto precomputed = Optimizer::getPrecomputedMinDeltaNodes(); double R = Optimizer::getNextNode(mindel); if (std::abs(R - precomputed[n]) > 1.E-9){ // this seems large, double-check pass = false; cout << "ERROR: mismatch in stored vs computed nodes for rule_mindelta rule" << endl; } } #endif }else if ((rule == TasGrid::rule_gausslegendre) || (rule == TasGrid::rule_gausslegendreodd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[5] = { 20, 36, 38, 38, 38 }; const double tols1[5] = { 1.E-10, 1.E-07, 1.E-07, 1.E-06, 1.E-06 }; const int depths2[5] = { 24, 36, 36, 36, 36 }; const double tols2[5] = { 1.E-10, 1.E-07, 1.E-07, 1.E-06, 1.E-06 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if (rule == TasGrid::rule_gausspatterson){ { TasGrid::TypeOneDRule oned = TasGrid::rule_gausspatterson; const int depths1[5] = { 20, 36, 38, 38, 38 }; const double tols1[5] = { 1.E-10, 1.E-07, 1.E-07, 1.E-06, 1.E-06 }; const int depths2[5] = { 24, 36, 36, 36, 36 }; const double tols2[5] = { 1.E-10, 1.E-07, 1.E-07, 1.E-06, 1.E-06 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if (rule == TasGrid::rule_customtabulated){ { TasGrid::TypeOneDRule oned = TasGrid::rule_customtabulated; const int depths1[5] = { 20, 36, 38, 38, 38 }; const double tols1[5] = { 1.E-10, 1.E-07, 1.E-07, 1.E-06, 1.E-06 }; const int depths2[5] = { 24, 36, 36, 36, 36 }; const double tols2[5] = { 1.E-10, 1.E-07, 1.E-07, 1.E-06, 1.E-06 }; if (testGlobalRule(&f21nx2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and testGlobalRule(&f21cos, oned, 0, alpha, beta, all_test_types, depths2, tols2)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if (rule == TasGrid::rule_fejer2){ { TasGrid::TypeOneDRule oned = TasGrid::rule_fejer2; const int depths1[5] = { 20, 40, 40, 40, 40 }; const double tols1[5] = { 1.E-14, 1.E-12, 1.E-12, 1.E-09, 1.E-09 }; if (testGlobalRule(&f21coscos, oned, 0, alpha, beta, all_test_types, depths1, tols1)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_gausschebyshev1) || (rule == TasGrid::rule_gausschebyshev1odd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 5.E-14, 1.E-05, 1.E-05, 1.E-04, 1.E-04 }; if (testGlobalRule(&f21constGC1, oned, 0, alpha, beta, all_test_types, depths1, tols1) and performGaussTransfromTest(oned)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_gausschebyshev2) || (rule == TasGrid::rule_gausschebyshev2odd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 1.1E-14, 1.E-05, 1.E-05, 1.E-04, 1.E-04 }; if (testGlobalRule(&f21constGC2, oned, 0, alpha, beta, all_test_types, depths1, tols1) and performGaussTransfromTest(oned)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_gaussgegenbauer) || (rule == TasGrid::rule_gaussgegenbauerodd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 1.E-11, 1.E-05, 1.E-05, 1.E-04, 1.E-04 }; if (testGlobalRule(&f21constGG, oned, 0, alpha, beta, all_test_types, depths1, tols1) and performGaussTransfromTest(oned)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_gaussjacobi) || (rule == TasGrid::rule_gaussjacobiodd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[5] = { 20, 20, 20, 20, 20 }; const double tols1[5] = { 1.E-08, 1.E-05, 1.E-05, 1.E-04, 1.E-04 }; if (testGlobalRule(&f21constGJ, oned, 0, alpha, beta, all_test_types, depths1, tols1) and performGaussTransfromTest(oned)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_gausslaguerre) || (rule == TasGrid::rule_gausslaguerreodd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[1] = { 20 }; const double tols1[1] = { 1.E-08 }; if (testGlobalRule(&f21constGGL, oned, 0, alpha, beta, quad_only, depths1, tols1) and performGaussTransfromTest(oned)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} }else if ((rule == TasGrid::rule_gausshermite) || (rule == TasGrid::rule_gausshermiteodd)){ { TasGrid::TypeOneDRule oned = rule; const int depths1[1] = { 20 }; const double tols1[1] = { 1.E-09 }; if (testGlobalRule(&f21constGH, oned, 0, alpha, beta, quad_only, depths1, tols1) and performGaussTransfromTest(oned)){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; }} } return pass; } bool ExternalTester::performGaussTransfromTest(TasGrid::TypeOneDRule oned) const{ //double alpha = 0.3, beta = 0.7; bool pass = true; int wfirst = 10, wsecond = 35, wthird = 15; if ((oned == TasGrid::rule_gausschebyshev1) || (oned == TasGrid::rule_gausschebyshev1odd)){ // Gauss-Chebyshev-1 translated to [4, 7], area = Maths::pi, integral of f(x) = 1 / x is Maths::pi * sqrt(7.0) / 14.0 TasGrid::TasmanianSparseGrid grid; grid.makeGlobalGrid(1, 1, 6, type_level, oned); double transa = 4.0, transb = 7.0; grid.setDomainTransform(&transa, &transb); auto w = grid.getQuadratureWeights(); auto p = grid.getNeededPoints(); int num_p = grid.getNumNeeded(); double sum = 0.0; for(int i=0; i Maths::num_tol){ cout << sum << " " << Maths::pi << endl; cout << "ERROR: sum of weight in transformed gauss-chebyshev-1 rule is off by: " << std::abs(sum - Maths::pi) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } sum = 0.0; for(int i=0; i w; grid.getQuadratureWeights(w); std::vector p = grid.getNeededPoints(); int num_p = grid.getNumNeeded(); double sum = 0.0; for(int i=0; i Maths::num_tol){ cout << sum << " " << 9.0 * Maths::pi / 8.0 << endl; cout << "ERROR: sum of weight in transformed gauss-chebyshev-2 rule is off by: " << std::abs(sum - 9.0 * Maths::pi / 8.0) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } sum = 0.0; for(int i=0; i Maths::num_tol){ cout << sum << " " << 8.1 << endl; cout << "ERROR: sum of weight in transformed gauss-genebauer rule is off by: " << std::abs(sum - 8.1) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } sum = 0.0; for(int i=0; i 1.E-10){ cout << "ERROR: disrepancy in transformed gauss-gegenbauer rule is: " << std::abs(sum - 389367.0 / 280.0) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } }else if ((oned == TasGrid::rule_gaussjacobi) || (oned == TasGrid::rule_gaussjacobiodd)){ // Gauss-Jacobi translated to [4, 7], area = 12.15, integral of f(x) = x^3 is 389367.0 / 280.0 TasGrid::TasmanianSparseGrid grid; grid.makeGlobalGrid(1, 1, 10, type_level, oned, 0, 3.0, 2.0); double transa = 4.0, transb = 7.0; grid.setDomainTransform(&transa, &transb); auto w = grid.getQuadratureWeights(); auto p = grid.getNeededPoints(); int num_p = grid.getNumNeeded(); double sum = 0.0; for(int i=0; i Maths::num_tol){ cout << sum << " " << 12.15 << endl; cout << "ERROR: sum of weight in transformed gauss-jacobi rule is off by: " << std::abs(sum - 12.15) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } sum = 0.0; for(int i=0; i 1.E-11){ cout << "ERROR: disrepancy in transformed gauss-jacobi rule is: " << std::abs(sum + 18.0 * (3.0 * Maths::pi * Maths::pi - 4.0) / pow(Maths::pi, 5.0)) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } }else if ((oned == TasGrid::rule_gausslaguerre) || (oned == TasGrid::rule_gausslaguerreodd)){ // Gauss-Laguerre, unbounded domain TasGrid::TasmanianSparseGrid grid; grid.makeGlobalGrid(2, 1, 6, type_level, oned, 0, 3.0); double transa[2] = {4.0, 3.0}, transb[2] = {0.5, 0.75}; grid.setDomainTransform(transa, transb); auto w = grid.getQuadratureWeights(); auto p = grid.getNeededPoints(); int num_p = grid.getNumNeeded(); double sum = 0.0; for(int i=0; i 10.0 * Maths::num_tol){ // without 10.0 the test fails on dpcpp with error 1.E-12 #else if (std::abs(sum - 96.0 * 512.0 / 27.0) > Maths::num_tol){ #endif cout << sum << " " << 96.0 * 512.0 / 27.0 << endl; cout << "ERROR: sum of weight in transformed gauss-laguerre rule is off by: " << std::abs(sum - 96.0 * 512.0 / 27.0) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } sum = 0.0; for(int i=0; i 6.E-7){ cout << "ERROR: disrepancy in transformed gauss-laguerre rule is: " << std::abs(sum - 15360.0 * 3573248.0 / 243.0) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } double test_x[2] = {3.0 + std::sqrt(2.0), 2.0 + std::sqrt(2.0)}; auto iw = grid.getInterpolationWeights(test_x); sum = 0.0; for(int i=0; i 2.E-9){ cout << "ERROR: nodal interpolation using gauss-laguerre: " << std::abs(sum - test_x[0] * test_x[0] * test_x[1] * test_x[1] * test_x[1]) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } }else if ((oned == TasGrid::rule_gausshermite) || (oned == TasGrid::rule_gausshermiteodd)){ // Gauss-Hermite, unbounded domain TasGrid::TasmanianSparseGrid grid; grid.makeGlobalGrid(2, 1, 6, type_level, oned, 0, 4.0); double transa[2] = {4.0, 3.0}, transb[2] = {0.5, 0.75}; grid.setDomainTransform(transa, transb); auto w = grid.getQuadratureWeights(); auto p = grid.getNeededPoints(); int num_p = grid.getNumNeeded(); double sum = 0.0; for(int i=0; i Maths::num_tol){ cout << sum << " " << 96.0 * 512.0 / 27.0 << endl; cout << "ERROR: sum of weight in transformed gauss-hermite rule is off by: " << std::abs(sum - (8.0 * Maths::pi / 3.0) * std::sqrt(6.0)) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } sum = 0.0; for(int i=0; i 4.E-8){ cout << "ERROR: disrepancy in transformed gauss-hermite rule is: " << std::abs(sum - 15360.0 * 3573248.0 / 243.0) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } double test_x[2] = {3.0 + std::sqrt(2.0), 2.0 + std::sqrt(2.0)}; auto iw = grid.getInterpolationWeights(test_x); sum = 0.0; for(int i=0; i 1.E-9){ cout << "ERROR: nodal interpolation using gauss-hermite: " << std::abs(sum - test_x[0] * test_x[0] * test_x[1] * test_x[1] * test_x[1]) << endl; cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } } return pass; } bool ExternalTester::testAllGlobal() const{ bool pass = true; std::vector rules = { TasGrid::rule_chebyshev, TasGrid::rule_chebyshevodd, TasGrid::rule_clenshawcurtis, TasGrid::rule_clenshawcurtis0, TasGrid::rule_fejer2, TasGrid::rule_leja, TasGrid::rule_lejaodd, TasGrid::rule_rleja, TasGrid::rule_rlejadouble2, TasGrid::rule_rlejadouble4, TasGrid::rule_rlejaodd, TasGrid::rule_rlejashifted, TasGrid::rule_rlejashiftedeven, TasGrid::rule_rlejashifteddouble, TasGrid::rule_maxlebesgue, TasGrid::rule_maxlebesgueodd, TasGrid::rule_minlebesgue, TasGrid::rule_minlebesgueodd, TasGrid::rule_mindelta, TasGrid::rule_mindeltaodd, TasGrid::rule_gausslegendre, TasGrid::rule_gausslegendreodd, TasGrid::rule_gausspatterson, TasGrid::rule_gausschebyshev1, TasGrid::rule_gausschebyshev1odd, TasGrid::rule_gausschebyshev2, TasGrid::rule_gausschebyshev2odd, TasGrid::rule_gaussgegenbauer, TasGrid::rule_gaussgegenbauerodd, TasGrid::rule_gaussjacobi, TasGrid::rule_gaussjacobiodd, TasGrid::rule_gausslaguerre, TasGrid::rule_gausslaguerreodd, TasGrid::rule_gausshermite, TasGrid::rule_gausshermiteodd, TasGrid::rule_customtabulated }; for(size_t i=0; i orders = { 0, 1, 2, 3, 4, -1 }; std::vector test_x; const BaseFunction* test_fn; bool bPass = true; for(int i=0; i<30; i++) { bool zero_order_diff_test = (orders[i / 5] == 0 and (all_test_types[i % 5] == type_nodal_differentiation or all_test_types[i % 5] == type_internal_differentiation)); test_fn = zero_order_diff_test ? &f11p0 : f; test_x = genRandom(test_fn->getNumInputs()); grid = makeLocalPolynomialGrid(test_fn->getNumInputs(), test_fn->getNumOutputs(), depths[i], orders[i / 5], rule); R = getError(test_fn, grid, all_test_types[i % 5], test_x); if (R.error > tols[i]) { bPass = false; cout << setw(18) << "ERROR: FAILED "; cout << setw(6) << IO::getRuleString(rule) << " order: " << orders[i / 5]; cout << setw(25) << testName(all_test_types[i % 5]) << " failed function: " << test_fn->getDescription(); cout << setw(10) << " observed: " << R.error << " expected: " << tols[i] << endl; } } return bPass; } bool ExternalTester::testSurplusRefinement(const BaseFunction *f, TasmanianSparseGrid &grid, double tol, TypeRefinement rtype, const int np[], const double errs[], int max_iter ) const{ for(int itr=0; itr errs[itr]) ){ cout << setw(18) << "ERROR: FAILED refinement test at iteration: " << itr << endl; cout << " expected: " << np[itr] << " " << errs[itr] << " computed: " << R.num_points << " " << R.error << endl; return false; } if (grid.isGlobal()){ grid.setSurplusRefinement(tol, 0); }else if (grid.isSequence()){ grid.setSurplusRefinement(tol, -1); TasmanianSparseGrid grid_copy(grid); // test the copy-constructor grid.makeGlobalGrid(1, 1, 1, type_level, rule_rleja); grid.copyGrid(&grid_copy); }else{ if (itr == 1){ // tests the array and vector overloads grid.setSurplusRefinement(tol, rtype, -1, std::vector()); }else{ grid.setSurplusRefinement(tol, rtype); } } } return true; } bool ExternalTester::testAnisotropicRefinement(const BaseFunction *f, TasmanianSparseGrid &grid, TypeDepth type, int min_growth, const int np[], const double errs[], int max_iter ) const{ for(int itr=0; itr errs[itr]) ){ cout << setw(18) << "ERROR: FAILED refinement test at iteration: " << itr << endl; cout << " expected: " << np[itr] << " " << errs[itr] << " computed: " << R.num_points << " " << R.error << endl; return false; } grid.setAnisotropicRefinement(type, min_growth, (grid.isGlobal()) ? 0 : -1); } return true; } bool ExternalTester::testDynamicRefinement(const BaseFunction *f, TasmanianSparseGrid &grid, TypeDepth type, double tolerance, TypeRefinement reftype, const std::vector &np, const std::vector &errs) const{ if (grid.isUsingConstruction()){ cout << "ERROR: Dynamic construction initialized for no reason." << endl; return false; } grid.beginConstruction(); if (!grid.isUsingConstruction()){ cout << "ERROR: Dynamic construction failed to initialize." << endl; return false; } size_t dims = (size_t) grid.getNumDimensions(); size_t outs = (size_t) grid.getNumOutputs(); for(size_t itr = 0; grid.getNumLoaded() < np.back(); itr++){ std::vector points; if (grid.isGlobal() || grid.isSequence() || grid.isFourier()){ if (itr == 1){ auto weights = grid.estimateAnisotropicCoefficients(type, 0); points = grid.getCandidateConstructionPoints(type, weights); }else{ points = grid.getCandidateConstructionPoints(type, 0); } }else{ points = grid.getCandidateConstructionPoints(tolerance, reftype); } size_t num_points = points.size() / dims; size_t max_points = (grid.isLocalPolynomial() || grid.isFourier()) ? 123 : 32; // do not compute all points from a batch, i.e., we don't want the less important points // compute only half the batch, but no more than max_points // local grids require more points, hence large max_points to reduce the total iterations // local grids do not include completely unimportant points, hence we can compute all points for small batches num_points = ((!grid.isLocalPolynomial()) || (num_points > 10)) ? num_points / 2 : num_points; num_points = std::min(num_points, max_points); std::vector pindex(num_points); for(size_t i=0; i x(&(points[i * dims]), &(points[i * dims]) + dims); std::vector y(outs); f->eval(x.data(), y.data()); if (i % 3 == 0){ // every third point uses the array interface for testing purpose grid.loadConstructedPoints(x.data(), 1, y.data()); }else{ grid.loadConstructedPoints(x, y); } } // make sure that getError() does not load values but only does evaluations if (grid.getNumNeeded() != 0){ cout << "ERROR: dynamic construction did not clear the needed points at iteration: " << itr << endl; return false; } if (grid.getNumLoaded() == 0){ cout << "ERROR: dynamic construction failed to load any tensors at iteration: " << itr << endl; return false; } TestResults R = getError(f, grid, type_internal_interpolation); //cout << "points = " << R.num_points << " err = " << R.error << std::endl; for(size_t i = 0; i < np.size(); i++){ if ((R.num_points >= np[i]) && (R.error > errs[i])){ cout << "ERROR: dynamic construction failed at iteration: " << itr << endl; cout << "function: " << f->getDescription() << " expected = " << np[i] << " " << errs[i] << " observed points = " << R.num_points << " error = " << R.error << std::endl; break; //return false; } } if (itr % 3 == 2){ grid.finishConstruction(); grid.beginConstruction(); } } grid.finishConstruction(); if (grid.isUsingConstruction()){ cout << "ERROR: Dynamic construction failed to finalize." << endl; return false; } TasmanianSparseGrid grid2; if (grid.isGlobal()){ // the goal here is to create a new grid by using only the points and values from the old grid // since we don't have the tensor data here, we create a global grid that is much larger (superset) of the current one // then the points will be loaded with a single command and only the loaded points will be used grid2 = makeGlobalGrid(grid.getNumDimensions(), grid.getNumOutputs(), (grid.getRule() == rule_rlejadouble4) ? 30 : 9, type_level, grid.getRule()); }else if (grid.isSequence()){ grid2 = makeSequenceGrid(grid.getNumDimensions(), grid.getNumOutputs(), 0, type_level, grid.getRule()); }else if (grid.isLocalPolynomial()){ grid2 = makeLocalPolynomialGrid(grid.getNumDimensions(), grid.getNumOutputs(), 0, grid.getOrder(), grid.getRule()); }else{ return true; } grid2.beginConstruction(); auto pnts = grid.getPoints(); std::vector vals; grid.evaluateBatch(pnts, vals); grid2.loadConstructedPoints(pnts, vals); grid2.finishConstruction(); if (grid.getNumLoaded() != grid2.getNumLoaded()){ cout << "ERROR: did not load a batch of points." << endl; return false; } std::vector res1, res2; std::vector xpnts = genRandom(10, grid.getNumDimensions()); grid.evaluateBatch(xpnts, res1); grid2.evaluateBatch(xpnts, res2); double err = 0.0; for(size_t i=0; i Maths::num_tol){ cout << "ERROR: failed evaluate after loading batch points. " << endl; return false; } return true; } bool ExternalTester::testAllPWLocal() const{ bool pass = true; int wfirst = 10, wsecond = 35, wthird = 15; { TasGrid::TypeOneDRule oned = TasGrid::rule_semilocalp; const std::vector depths1(30, 8); // Tolerances for semi-local quadrature (column 1), interpolation (columns 2-3), and differentiation (columns 4-5). const std::vector tols1 = { 1.E-03, 5.E-01, 5.E-01, 5.E-01, 5.E-01, // order 0 1.E-03, 1.E-03, 1.E-03, 1.E-01, 1.E-01, // order 1 1.E-07, 1.E-04, 1.E-04, 1.E-03, 1.E-03, // order 2 1.E-07, 1.E-05, 1.E-05, 1.E-04, 1.E-04, // order 3 1.E-07, 4.E-06, 4.E-06, 4.E-05, 4.E-05, // order 4 1.E-07, 4.E-06, 4.E-06, 4.E-05, 4.E-05 }; // order -1 if (testLocalPolynomialRule(&f21nx2, oned, depths1.data(), tols1.data())){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } } { TasGrid::TypeOneDRule oned = TasGrid::rule_localp; const std::vector depths1(30, 8); // Tolerances for local quadrature (column 1), interpolation (columns 2-3), and differentiation (columns 4-5). const std::vector tols1 = { 1.E-03, 5.E-01, 5.E-01, 5.E-01, 5.E-01, // order 0 1.E-03, 1.E-03, 1.E-03, 1.E-01, 1.E-01, // order 1 1.E-07, 1.E-04, 1.E-04, 1.E-03, 1.E-03, // order 2 1.E-07, 1.E-05, 1.E-05, 1.E-04, 1.E-04, // order 3 1.E-07, 4.E-06, 4.E-06, 4.E-05, 4.E-05, // order 4 1.E-07, 4.E-06, 4.E-06, 4.E-05, 4.E-05 }; // order -1 if (testLocalPolynomialRule(&f21nx2, oned, depths1.data(), tols1.data())){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } } { TasGrid::TypeOneDRule oned = TasGrid::rule_localpb; const std::vector depths1(30, 8); // Tolerances for local-boundary quadrature (column 1), interpolation (columns 2-3), and differentiation (columns 4-5). const std::vector tols1 = { 1.E-03, 5.E-01, 5.E-01, 5.E-01, 5.E-01, // order 0 1.E-03, 1.E-03, 1.E-03, 5.E-01, 5.E-01, // order 1 1.E-07, 1.E-04, 1.E-04, 1.E-02, 1.E-02, // order 2 1.E-07, 1.E-05, 1.E-05, 1.E-03, 1.E-03, // order 3 1.E-07, 9.E-06, 9.E-06, 9.E-05, 9.E-05, // order 4 1.E-06, 2.E-05, 2.E-05, 2.E-04, 2.E-04 }; // order -1 if (testLocalPolynomialRule(&f21sincosaxis, oned, depths1.data(), tols1.data())){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } } { TasGrid::TypeOneDRule oned = TasGrid::rule_localp0; const std::vector depths1(30, 8); // Tolerances for local-zero quadrature (column 1), interpolation (columns 2-3), and differentiation (columns 4-5). const std::vector tols1 = { 1.E-03, 5.E-01, 5.E-01, 5.E-01, 5.E-01, // order 0 1.E-03, 2.E-04, 2.E-04, 2.E-02, 2.E-02, // order 1 1.E-09, 1.E-06, 1.E-06, 1.E-04, 1.E-04, // order 2 1.E-09, 3.E-08, 3.E-08, 3.E-06, 3.E-06, // order 3 1.E-09, 4.E-09, 4.E-09, 4.E-08, 4.E-08, // order 4 1.E-09, 4.E-09, 4.E-09, 4.E-08, 4.E-08}; // order -1 if (testLocalPolynomialRule(&f21coscos, oned, depths1.data(), tols1.data())){ if (verbose) cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(oned) << setw(wthird) << "FAIL" << endl; pass = false; } } { TasGrid::TasmanianSparseGrid grid = makeLocalPolynomialGrid(2, 1, 4, 1); std::vector indx, pntr; std::vector vals; std::vector pnts = genRandom(10, 2); grid.evaluateSparseHierarchicalFunctions(pnts, pntr, indx, vals); getError(&f21nx2, grid, type_internal_interpolation); // this is done to load the values const double *coeff = grid.getHierarchicalCoefficients(); std::vector y(10); grid.evaluateBatch(pnts.data(), 10, y.data()); for(int i=0; i<10; i++){ for(int j=pntr[i]; j Maths::num_tol){ cout << "Error in evaluateSparseHierarchicalFunctions() (localp)" << endl; pass = false; } } } wfirst = 11; wsecond = 34; if (pass){ cout << setw(wfirst) << "Rules" << setw(wsecond) << "local polynomial" << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rules" << setw(wsecond) << "local polynomial" << setw(wthird) << "FAIL" << endl; } return pass; } bool ExternalTester::testLocalWaveletRule(const BaseFunction *f, const int depths[], const double tols[], bool flavor) const{ TestResults R; int orders[2] = { 1, 3 }; std::vector x = genRandom(f->getNumInputs()); bool bPass = true; for(auto acc : available_acc){ for(int i=0; i<10; i++){ auto grid = makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), depths[i], orders[i/5]); grid.enableAcceleration(acc, (gpuid == -1) ? 0 : gpuid); grid.favorSparseAcceleration(flavor); R = getError(f, grid, all_test_types[i%5], x); if (R.error > tols[i]){ bPass = false; cout << setw(18) << "ERROR: FAILED "; cout << setw(6) << IO::getRuleString(rule_wavelet); cout << " order: " << orders[i/5]; cout << " " << testName(all_test_types[i%5]) << " failed function: " << f->getDescription(); cout << setw(10) << " observed: " << R.error << " expected: " << tols[i] << endl; } } } return bPass; } bool ExternalTester::testAllWavelet() const{ bool pass = true; // Depths and tolerances for quadrature (column 1), interpolation (columns 2-3), and differentiation (columns 4-5). const int depths1[10] = { 7, 7, 7, 7, 7, // order 1 5, 5, 5, 5, 5 }; // order 3 const double tols1[10] = { 5.E-05, 1.E-04, 1.E-04, 5E-02, 5E-02, // order 1 1.E-08, 1.E-07, 1.E-07, 5E-05, 5E-05 }; // order 3 int wfirst = 11, wsecond = 34, wthird = 15; if (testLocalWaveletRule(&f21nx2, depths1, tols1, true) and testLocalWaveletRule(&f21nx2, depths1, tols1, false)){ cout << setw(wfirst) << "Rules" << setw(wsecond) << "wavelet" << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rule" << setw(wsecond) << IO::getRuleString(rule_wavelet) << setw(wthird) << "FAIL" << endl; pass = false; }{ TasGrid::TasmanianSparseGrid grid; grid.makeWaveletGrid(2, 1, 2, 1); std::vector indx, pntr; std::vector vals; std::vector pnts = genRandom(10, 2); grid.evaluateSparseHierarchicalFunctions(pnts, pntr, indx, vals); getError(&f21nx2, grid, type_internal_interpolation); // this is done to load the values const double *coeff = grid.getHierarchicalCoefficients(); std::vector y(10); grid.evaluateBatch(pnts.data(), 10, y.data()); for(int i=0; i<10; i++){ for(int j=pntr[i]; j Maths::num_tol){ cout << "Error in evaluateSparseHierarchicalFunctions() (wavelet)" << endl; cout << y[i] << endl; pass = false; } } std::vector v(10 * grid.getNumPoints()); getError(&f21nx2, grid, type_internal_interpolation); grid.evaluateHierarchicalFunctions(pnts, v); coeff = grid.getHierarchicalCoefficients(); grid.evaluateBatch(pnts.data(), 10, y.data()); for(int i=0; i<10; i++){ for(int j=0; j Maths::num_tol){ cout << "Error in getHierarchicalCoefficients() (wavelet)" << endl; cout << y[i] << endl; pass = false; } } } return pass; } bool ExternalTester::testAllFourier() const{ bool pass = true; const int depths1[5] = { 6, 6, 6, 6, 6 }; const int depths2[5] = { 5, 5, 5, 5, 5 }; const double tols1[5] = { 1.E-11, 1.E-06, 1.E-06, 5.E-04, 1.E-05 }; const double tols2[5] = { 1.E-11, 1.E-02, 1.E-02, 5.E-01, 1.E-01 }; int wfirst = 11, wsecond = 34, wthird = 15; if (testGlobalRule(&f21expsincos, TasGrid::rule_fourier, 0, 0, 0, all_test_types, depths1, tols1) && testGlobalRule(&f21expsincos, TasGrid::rule_fourier, 0, 0, 0, all_test_types, depths2, tols2)){ cout << setw(wfirst) << "Rules" << setw(wsecond) << "fourier" << setw(wthird) << "Pass" << endl; }else{ cout << setw(wfirst) << "Rules" << setw(wsecond) << "fourier" << setw(wthird) << "FAIL" << endl; pass = false; }{ TasGrid::TasmanianSparseGrid grid; grid.makeFourierGrid(2, 1, 4, TasGrid::type_level); int num_eval = 10; std::vector pnts = genRandom(num_eval, std::vector(2, 0.0), std::vector(2, 1.0)); // generate 2D point in [0, 1] int num_points = grid.getNumPoints(); std::vector y, v; getError(&f21expsincos, grid, type_internal_interpolation); const double *coeff = grid.getHierarchicalCoefficients(); // coeff = [fourier_coeff_1.real(), fourier_coeff_1.imag(), fourier_coeff_2.real(), ...] grid.evaluateHierarchicalFunctions(pnts, v); grid.evaluateBatch(pnts, y); for(int i=0; i Maths::num_tol){ cout << "Error in getHierarchicalCoefficients() (fourier)" << endl; cout << "y["< ref_integral(1); f21expsincos.getIntegral(ref_integral.data()); if (std::abs(std::accumulate(integrals.begin() + 1, integrals.end(), 0.0)) > Maths::num_tol){ cout << "Error in zeors for integrateHierarchicalFunctions() (fourier)" << endl; pass = false; } if (std::abs(coeff[0] * integrals[0] - 0.25 * ref_integral[0]) > Maths::num_tol){ cout << "Error in value for integrateHierarchicalFunctions() (fourier)" << endl; pass = false; } grid.updateFourierGrid(5, type_level); if (grid.getNumNeeded() != 756){ cout << "Error in num points for updateFourierGrid()" << endl; pass = false; } } return pass; } bool ExternalTester::testAllRefinement() const{ TasmanianSparseGrid grid; bool pass = true; { const BaseFunction *f = &f21nx2; grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 3, type_iptotal, rule_leja); int np[13] = { 10, 15, 21, 28, 36, 45, 55, 66, 78, 91, 105, 118, 130 }; double err[13] = { 2, 2.E-1, 5.E-1, 2.E-2, 4.E-2, 2.E-3, 4.E-3, 2.E-4, 2.E-4, 2.E-5, 2.E-5, 8.E-7, 8.E-7 }; if (!testSurplusRefinement(f, grid, 1.E-6, refine_classic, np, err, 13)){ cout << "ERROR: failed leja surplus refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21coscos; int np[9] = { 21, 24, 30, 39, 49, 60, 72, 79, 85 }; double err[9] = { 2.E-1, 7.E-3, 2.E-2, 3.E-4, 6.E-4, 4.E-6, 9.E-6, 5.E-7, 5.E-7 }; grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 5, type_iptotal, rule_rleja); if (!testSurplusRefinement(f, grid, 1.E-6, refine_classic, np, err, 9)){ cout << "ERROR: failed rleja global surplus refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21coscos; int np[9] = { 21, 24, 30, 39, 49, 60, 72, 79, 85 }; double err[9] = { 2.E-1, 7.E-3, 2.E-2, 3.E-4, 6.E-4, 4.E-6, 9.E-6, 5.E-7, 5.E-7 }; grid.makeSequenceGrid(f->getNumInputs(), f->getNumOutputs(), 5, type_iptotal, rule_rleja); if (!testSurplusRefinement(f, grid, 1.E-6, refine_classic, np, err, 9)){ cout << "ERROR: failed rleja sequence surplus refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 2, rule_semilocalp); int np[8] = { 29, 65, 145, 321, 705, 1521, 2753, 3569 }; double err[8] = { 4.E-2, 1.E-2, 1.E-3, 2.E-4, 4.E-5, 5.E-6, 1.E-6, 5.E-7 }; if (!testSurplusRefinement(f, grid, 1.E-6, refine_classic, np, err, 8)){ cout << "ERROR: failed semi-local classic refinement for " << f->getDescription() << endl; pass = false; } grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 2, rule_semilocalp); }{ const BaseFunction *f = &f21nx2; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 2, rule_semilocalp); int np[8] = { 29, 65, 145, 321, 705, 1521, 2753, 3569 }; double err[8] = { 4.E-2, 1.E-2, 1.E-3, 2.E-4, 4.E-5, 5.E-6, 1.E-6, 5.E-7 }; if (!testSurplusRefinement(f, grid, 1.E-6, refine_parents_first, np, err, 8)){ cout << "ERROR: failed semi-local parents refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 2, 2, rule_semilocalp); int np[6] = { 13, 29, 65, 145, 321, 545 }; double err[6] = { 8.E-02, 5.E-02, 7.E-03, 2.E-03, 3.E-04, 6.E-05 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_direction_selective, np, err, 6)){ cout << "ERROR: failed semi-local direction refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 2, 2, rule_semilocalp); int np[6] = { 13, 29, 65, 145, 321, 545 }; double err[6] = { 8.E-02, 5.E-02, 7.E-03, 2.E-03, 3.E-04, 6.E-05 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_fds, np, err, 6)){ cout << "ERROR: failed semi-local fds refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 1, rule_localp); int np[10] = { 29, 65, 145, 321, 705, 1537, 3321, 6981, 13517, 19113 }; double err[10] = { 4.E-2, 2.E-2, 6.E-3, 2.E-3, 6.E-4, 2.E-4, 6.E-5, 2.E-5, 6.E-6, 2.E-6 }; if (!testSurplusRefinement(f, grid, 1.E-6, refine_classic, np, err, 10)){ cout << "ERROR: failed localp classic refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 1, rule_localp); int np[10] = { 29, 65, 145, 321, 705, 1537, 3321, 6981, 13517, 19113 }; double err[10] = { 4.E-2, 2.E-2, 6.E-3, 2.E-3, 6.E-4, 2.E-4, 6.E-5, 2.E-5, 6.E-6, 2.E-6 }; if (!testSurplusRefinement(f, grid, 1.E-6, refine_parents_first, np, err, 10)){ cout << "ERROR: failed localp parents refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 2, 1, rule_localp); int np[8] = { 13, 29, 65, 145, 321, 673, 1233, 1433 }; double err[8] = { 1.E-01, 5.E-02, 2.E-02, 5.E-03, 2.E-03, 6.E-04, 2.E-04, 1.E-04 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_direction_selective, np, err, 8)){ cout << "ERROR: failed localp direction refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 2, 1, rule_localp); int np[8] = { 13, 29, 65, 145, 321, 673, 1233, 1433 }; double err[8] = { 1.E-01, 5.E-02, 2.E-02, 5.E-03, 2.E-03, 6.E-04, 2.E-04, 1.E-04 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_fds, np, err, 8)){ cout << "ERROR: failed localp fds refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21sincosaxis; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 1, rule_localpb); int np[7] = { 37, 77, 157, 317, 637, 1277, 2317 }; double err[7] = { 3.E-01, 5.E-02, 2.E-02, 4.E-03, 7.E-04, 3.E-04, 1.E-04 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_classic, np, err, 7)){ cout << "ERROR: failed localp-boundary fds refinement for " << f->getDescription() << endl; } }{ const BaseFunction *f = &f21sharp; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 5, 2, rule_localp); int np[9] = { 145, 277, 493, 977, 1813, 2773, 4085, 6013, 8549 }; double err[9] = { 8.E-1, 7.E-1, 6.E-1, 5.E-1, 2.E-1, 5.E-2, 3.E-2, 5.E-3, 8.E-4 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_stable, np, err, 9)){ cout << "ERROR: failed localp stable refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21coscos; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 2, rule_localp0); int np[6] = { 49, 129, 321, 769, 1761, 2209 }; double err[6] = { 2.E-3, 3.E-4, 5.E-5, 7.E-6, 8.E-7, 5.E-7 }; if (!testSurplusRefinement(f, grid, 1.E-6, refine_classic, np, err, 6)){ cout << "ERROR: failed localp-zero classic refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21coscos; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 2, rule_localp0); int np[6] = { 49, 129, 321, 769, 1761, 2209 }; double err[6] = { 2.E-3, 3.E-4, 5.E-5, 7.E-6, 8.E-7, 5.E-7 }; if (!testSurplusRefinement(f, grid, 1.E-6, refine_parents_first, np, err, 6)){ cout << "ERROR: failed localp-zero parents refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21coscos; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 2, 2, rule_localp0); int np[4] = { 17, 49, 129, 305 }; double err[4] = { 7.E-03, 2.E-03, 4.E-04, 4.E-05 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_direction_selective, np, err, 4)){ cout << "ERROR: failed localp-zero direction refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21coscos; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 2, 2, rule_localp0); int np[4] = { 17, 49, 129, 305 }; double err[4] = { 7.E-03, 2.E-03, 4.E-04, 4.E-05 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_fds, np, err, 4)){ cout << "ERROR: failed localp-zero fds refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 2, 0, rule_localp); int np[5] = { 21, 81, 297, 1053, 3637 }; double err[5] = { 3.E-1, 2.E-1, 6.E-2, 3E-2, 8.5E-3 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_fds, np, err, 5)){ cout << "ERROR: failed pwc fds refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21coscos; grid.makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), 2, 1); int np[7] = { 49, 81, 193, 449, 993, 1921, 1937 }; double err[7] = { 6.E-02, 3.E-02, 6.E-03, 3.E-03, 6.E-04, 3.E-04, 2.E-04 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_classic, np, err, 7)){ cout << "ERROR: failed wavelet classic refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21coscos; grid.makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), 2, 1); int np[7] = { 49, 81, 193, 449, 993, 1921, 1937 }; double err[7] = { 6.E-02, 3.E-02, 6.E-03, 3.E-03, 6.E-04, 3.E-04, 2.E-04 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_parents_first, np, err, 7)){ cout << "ERROR: failed wavelet parents refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), 2, 1); int np[6] = { 49, 113, 257, 561, 1113, 1481 }; double err[6] = { 6.E-02, 1.E-02, 5.E-03, 1.E-03, 5.E-04, 1.E-04 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_direction_selective, np, err, 6)){ cout << "ERROR: failed wavelet direction refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21coscos; grid.makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), 2, 1); int np[7] = { 49, 81, 161, 385, 889, 1737, 1769 }; double err[7] = { 6.E-02, 3.E-02, 6.E-03, 3.E-03, 6.E-04, 3.E-04, 2.E-04 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_fds, np, err, 7)){ cout << "ERROR: failed wavelet fds refinement for " << f->getDescription() << endl; pass = false; } }{ const BaseFunction *f = &f21nx2; grid.makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), 1, 3); int np[3] = { 65, 161, 369 }; double err[3] = { 5.E-03, 5.E-04, 5.E-05 }; if (!testSurplusRefinement(f, grid, 1.E-4, refine_stable, np, err, 3)){ cout << "ERROR: failed wavelet stable refinement for " << f->getDescription() << endl; pass = false; } } cout << " Refinement surplus" << setw(15) << ((pass) ? "Pass" : "FAIL") << endl; bool pass2 = true; { const BaseFunction *f = &f21aniso; grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 3, type_iptotal, rule_leja); int np[40] = { 10, 15, 21, 28, 29, 30, 31, 32, 34, 35, 37, 40, 41, 45, 49, 54, 59, 64, 70, 77, 84, 92, 100, 108, 117, 126, 135, 145, 155, 165, 176, 187, 198, 210, 212, 224, 237, 248, 251, 263 }; double errs[40] = { 9.04e-01, 4.24e-01, 5.73e-01, 2.78e-01, 3.15e-01, 2.49e-01, 3.00e-01, 8.85e-02, 9.30e-02, 9.67e-02, 2.06e-01, 3.03e-01, 5.24e-02, 4.63e-02, 5.85e-02, 5.11e-02, 9.80e-03, 2.71e-02, 5.42e-03, 7.85e-03, 6.21e-03, 5.41e-03, 2.56e-03, 3.32e-03, 5.18e-04, 6.14e-04, 3.66e-04, 4.87e-04, 8.19e-05, 2.58e-04, 5.76e-05, 5.54e-05, 5.22e-05, 4.89e-05, 4.68e-05, 8.92e-06, 2.20e-05, 5.56e-06, 5.14e-06, 5.79e-06 }; if (!testAnisotropicRefinement(f, grid, type_iptotal, 1, np, errs, 40)){ cout << "ERROR: failed anisotropic refinement using leja iptotal nodes for " << f->getDescription() << endl; pass2 = false; } }{ const BaseFunction *f = &f21curved; grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 3, type_iptotal, rule_leja); int np[10] = { 10, 12, 17, 24, 32, 34, 41, 42, 57, 59 }; double errs[10] = { 9.48e-03, 9.50e-03, 6.85e-03, 5.11e-04, 6.26e-05, 7.11e-06, 5.07e-06, 5.19e-06, 1.17e-08, 1.86e-08 }; if (!testAnisotropicRefinement(f, grid, type_ipcurved, 1, np, errs, 7)){ cout << "ERROR: failed anisotropic refinement (global) using leja ipcurved nodes for " << f->getDescription() << endl; pass2 = false; } }{ const BaseFunction *f = &f21curved; grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 3, type_iptotal, rule_clenshawcurtis); int np[3] = { 13, 21, 29 }; double errs[3] = { 6.12e-04, 6.05e-04, 1.33e-08 }; if (!testAnisotropicRefinement(f, grid, type_ipcurved, 1, np, errs, 3)){ cout << "ERROR: failed anisotropic refinement using clenshaw-curtis ipcurved nodes for " << f->getDescription() << endl; pass2 = false; } }{ const BaseFunction *f = &f21curved; grid.makeSequenceGrid(f->getNumInputs(), f->getNumOutputs(), 3, type_iptotal, rule_leja); grid.enableAcceleration(accel_none); int np[10] = { 10, 12, 17, 24, 32, 34, 41, 42, 57, 59 }; double errs[10] = { 9.48e-03, 9.50e-03, 6.85e-03, 5.11e-04, 6.26e-05, 7.11e-06, 5.07e-06, 5.19e-06, 1.17e-08, 1.86e-08 }; if (!testAnisotropicRefinement(f, grid, type_ipcurved, 1, np, errs, 7)){ cout << "ERROR: failed anisotropic refinement (sequence) using leja ipcurved nodes for " << f->getDescription() << endl; pass2 = false; } }{ const BaseFunction *f = &f21c1c2periodic; grid.makeFourierGrid(f->getNumInputs(), f->getNumOutputs(), 3, type_hyperbolic); grid.setDomainTransform({-1.0, -1.0}, {1.0, 1.0}); int np[5] = { 17, 35, 111, 273, 759 }; double errs[5] = { 1.28e-2, 2.80e-3, 1.97e-4, 6.78e-5, 5.65e-5 }; if (!testAnisotropicRefinement(f, grid, type_hyperbolic, 1, np, errs, 5)){ cout << "ERROR: failed anisotropic refinement using Fourier hyperbolic nodes for " << f->getDescription() << endl; pass2 = false; } }{ const BaseFunction *f = &f21c1c2periodic; grid.makeFourierGrid(f->getNumInputs(), f->getNumOutputs(), 3, type_level); grid.enableAcceleration(accel_cpu_blas); grid.setDomainTransform({-1.0, -1.0}, {1.0, 1.0}); int np[5] = { 81, 135, 297, 783, 2295 }; double errs[5] = { 1.32e-3, 1.92e-4, 6.75e-5, 5.67e-5, 2.11e-6 }; if (!testAnisotropicRefinement(f, grid, type_hyperbolic, 1, np, errs, 5)){ cout << "ERROR: failed anisotropic refinement using Fourier level nodes for " << f->getDescription() << endl; pass2 = false; } } cout << " Refinement anisotropic" << setw(15) << ((pass2) ? "Pass" : "FAIL") << endl; bool pass5 = true; { const BaseFunction *f = &f21c1c2periodic; grid.makeFourierGrid(f->getNumInputs(), f->getNumOutputs(), 8, type_hyperbolic); double transform_a[2] = {-1.0, -1.0}; double transform_b[2] = { 1.0, 1.0}; grid.setDomainTransform(transform_a, transform_b); loadValues(f, grid); std::vector weights; grid.estimateAnisotropicCoefficients(type_hyperbolic, 0, weights); double aniso_ratio = ((double) weights[0]) / ((double) weights[1]); if (std::abs(aniso_ratio - 0.75) > 0.05){ pass5 = false; cout << "ERROR: failed estimating anisotropic coefficients for Fourier grid with " << f->getDescription() << endl; cout << "Anisotropy ratio should be 3/4 but instead is " << aniso_ratio << endl; } } cout << " Estimate anisotropy Fourier" << setw(15) << ((pass5) ? "Pass" : "FAIL") << endl; bool pass3 = true; { const BaseFunction *f = &f21aniso; std::vector np = { 29, 45, 65, 129, 193, 241, 289, 321, 417}; std::vector err = {0.06, 0.02, 0.008, 0.002, 0.0015, 0.0009, 3.E-4, 5.E-5, 1.E-5}; grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 4, type_level, rule_clenshawcurtis); if (!testDynamicRefinement(f, grid, type_iptotal, -1.0, refine_none, np, err)){ cout << "ERROR: failed dynamic anisotropic refinement using iptotal and clenshaw-curtis nodes for " << f->getDescription() << endl; pass3 = false; } }{ const BaseFunction *f = &f21aniso; std::vector np = { 29, 45, 97, 129, 321, 385, 417, 449}; std::vector err = {0.06, 0.02, 0.01, 0.001, 3.E-4, 3.E-4, 3.E-5, 3.E-5}; grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 4, type_level, rule_clenshawcurtis); if (!testDynamicRefinement(f, grid, type_ipcurved, -1.0, refine_none, np, err)){ cout << "ERROR: failed dynamic anisotropic refinement using ipcurved and clenshaw-curtis nodes for " << f->getDescription() << endl; pass3 = false; } }{ const BaseFunction *f = &f21aniso; std::vector np = { 32, 71, 105, 115, 168, 226, 291, 354, 473, 505}; std::vector err = {0.5, 2.E-2, 1.E-2, 9.E-3, 5.E-3, 2.E-3, 8.E-4, 3.E-4, 1.E-4, 5.E-5}; grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 20, type_iphyperbolic, rule_rlejadouble4); if (!testDynamicRefinement(f, grid, type_iphyperbolic, -1.0, refine_none, np, err)){ cout << "ERROR: failed dynamic anisotropic refinement using iphyperbolic and rule_rlejadouble4 nodes for " << f->getDescription() << endl; } }{ const BaseFunction *f = &f21aniso; std::vector np = { 27, 35, 39, 47, 55, 71, 87, 137, 162, 204, 228, 297}; std::vector err = {5.E-1, 3.E-1, 1.E-1, 8.E-2, 4.E-2, 2.E-2, 4.E-3, 5.E-4, 2.E-4, 4.E-5, 1.E-5, 3.E-6}; grid.makeSequenceGrid(f->getNumInputs(), f->getNumOutputs(), 7, type_level, rule_leja); if (!testDynamicRefinement(&f21aniso, grid, type_iptotal, -1.0, refine_none, np, err)){ cout << "ERROR: failed dynamic anisotropic refinement using iptotal and leja nodes for " << f->getDescription() << endl; pass3 = false; } } cout << " Construction dynamic/global" << setw(15) << ((pass3) ? "Pass" : "FAIL") << endl; bool pass4 = true; { const BaseFunction *f = &f21aniso; std::vector np = { 23, 38, 62, 104, 171, 280, 403, 645, 685}; std::vector err = {5.E-1, 3.E-1, 2.E-1, 8.E-2, 4.E-2, 8.E-3, 3.E-3, 1.E-3, 7.E-4}; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 1, rule_localp); if (!testDynamicRefinement(&f21aniso, grid, type_iptotal, 1.E-3, refine_classic, np, err)){ cout << "ERROR: failed dynamic surplus classic refinement using localp linear rule " << f->getDescription() << endl; pass4 = false; } }{ const BaseFunction *f = &f21aniso; std::vector np = { 23, 38, 62, 104, 171, 280, 403, 506}; std::vector err = {5.E-1, 3.E-1, 2.E-1, 8.E-2, 4.E-2, 8.E-3, 3.E-3, 1.E-3}; grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 3, 1, rule_semilocalp); if (!testDynamicRefinement(&f21aniso, grid, type_iptotal, 1.E-3, refine_fds, np, err)){ cout << "ERROR: failed dynamic surplus classic refinement using localp linear rule " << f->getDescription() << endl; pass4 = false; } }{ const BaseFunction *f = &f21aniso; std::vector np = { 23, 38, 64, 120, 171, 280, 403, 500}; std::vector err = {5.E-1, 3.E-1, 3.E-1, 2.E-1, 6.E-2, 3.E-2, 2.E-2, 6.E-3}; grid.makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), 3, 1); if (!testDynamicRefinement(&f21aniso, grid, type_iptotal, 1.E-3, refine_stable, np, err)){ cout << "ERROR: failed dynamic surplus classic refinement using wavelet linear rule " << f->getDescription() << endl; pass4 = false; } } cout << " Construction dynamic/local" << setw(15) << ((pass4) ? "Pass" : "FAIL") << endl; bool pass6 = true; { const BaseFunction *f = &f21c1c2periodic; std::vector np = { 5, 21, 51, 189, 297, 1377}; std::vector err = {5.E-1, 3.E-2, 1.E-2, 3.E-3, 5.E-4, 1.E-4}; grid.makeFourierGrid(f->getNumInputs(), f->getNumOutputs(), 2, type_level); grid.setDomainTransform({-1.0, -1.0}, {1.0, 1.0}); if (!testDynamicRefinement(f, grid, type_iphyperbolic, -1.0, refine_none, np, err)){ cout << "ERROR: failed dynamic anisotropic refinement using Fourier grid for " << f->getDescription() << endl; pass6 = false; } } cout << " Construction dynamic/fourier" << setw(15) << ((pass6) ? "Pass" : "FAIL") << endl; return (pass && pass2 && pass3 && pass4 && pass5 && pass6); } bool ExternalTester::testAllDomain() const{ TasmanianSparseGrid grid; bool pass1 = true; cout << std::scientific; cout.precision(16); { const BaseFunction *f = &f21nx2aniso; int np[5] = {1, 3, 7, 15, 29}; double errs[5] = {9.E-1, 9.E-1, 2.E-1, 2.E-1, 2.E-2 }; int aiso_weights[2] = { 2, 1 }; for(int i=0; i<5; i++){ grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), i, TasGrid::type_level, TasGrid::rule_clenshawcurtis, aiso_weights); TestResults R = getError(f, grid, type_internal_interpolation); if ((R.num_points != np[i]) || (R.error>errs[i])){ cout << "Using clenshaw-curtis rule" << endl; cout << "Failed anisotropic grid test for " << f->getDescription() << " number of points = " << R.num_points << " expacted: " << np[i] << " error = " << R.error << " expected: " << errs[i] << endl; pass1 = false; } } }{ const BaseFunction *f = &f21nx2aniso; int np[5] = {5, 10, 15, 28, 37}; double errs[5] = {3.E-1, 3.E-1, 5.E-2, 2.E-2, 2.E-3}; int aiso_weights[2] = {2, 1}; for(int i=0; i<5; i++){ grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), i+2, TasGrid::type_level, TasGrid::rule_gausslegendre, aiso_weights); TestResults R = getError(f, grid, type_integration); if ((R.num_points != np[i]) || (R.error>errs[i])){ cout << "Using gauss-legendre rule" << endl; cout << "Failed anisotropic grid test for " << f->getDescription() << " number of points = " << R.num_points << " expacted: " << np[i] << " error = " << R.error << " expected: " << errs[i] << endl; pass1 = false; } } }{ const BaseFunction *f = &f21nx2aniso; int np[5] = {36, 42, 49, 56, 64}; double errs[5] = {5.E-2, 5.E-2, 5.E-3, 5.E-3, 3.E-3 }; int aiso_weights[2] = { 2, 1 }; for(int i=0; i<5; i++){ grid.makeSequenceGrid(f->getNumInputs(), f->getNumOutputs(), i+10, TasGrid::type_level, TasGrid::rule_leja, aiso_weights); TestResults R = getError(f, grid, type_internal_interpolation); if ((R.num_points != np[i]) || (R.error>errs[i])){ cout << "Using leja rule" << endl; cout << "Failed anisotropic grid test for " << f->getDescription() << " number of points = " << R.num_points << " expacted: " << np[i] << " error = " << R.error << " expected: " << errs[i] << endl; pass1 = false; } } } cout << " Domain anisotropic" << setw(15) << ((pass1) ? "Pass" : "FAIL") << endl; bool pass2 = true; { const BaseFunction *f = &f21expDomain; double errs[5] = {3.E-5, 2.E-7, 2.E-8, 6.E-10, 4.E-11 }; double errs2[5] = {1.E-5, 2.E-6, 6.E-8, 6.E-9, 8.E-11 }; double errs3[5] = {6.E-2, 1.E-2, 5.E-3, 6.E-4, 6.E-5 }; double transform_a[2] = { 3.0, -3.0 }; double transform_b[2] = { 4.0, 2.0 }; for(int i=0; i<5; i++){ grid.makeSequenceGrid(f->getNumInputs(), f->getNumOutputs(), i+5, TasGrid::type_level, TasGrid::rule_leja); grid.setDomainTransform(transform_a, transform_b); auto needed_points = grid.getNeededPoints(); int num_needed = grid.getNumNeeded(); TestResults R = getError(f, grid, type_integration); if (R.error > errs[i]){ cout << "Using leja rule" << endl; cout << "Failed domain transform test for " << f->getDescription() << " error = " << R.error << " expected: " << errs[i] << endl; pass2 = false; } std::vector test_x = {3.314, -1.71732}; R = getError(f, grid, type_nodal_interpolation, test_x); if (R.error > errs2[i]){ cout << "Using leja rule" << endl; cout << "Failed domain transform test interpolation for " << f->getDescription() << " error = " << R.error << " expected: " << errs[i] << endl; pass2 = false; } R = getError(f, grid, type_internal_interpolation, test_x); if (R.error > errs3[i]){ cout << "Using leja rule" << endl; cout << "Failed domain transform test interpolation for " << f->getDescription() << " error = " << R.error << " expected: " << errs[i] << endl; pass2 = false; } auto loaded_points = grid.getLoadedPoints(); for(int j=0; jgetNumInputs(); j++){ if (std::abs(needed_points[j] - loaded_points[j]) > Maths::num_tol){ cout << "Mismatch between needed and loaded points" << endl; pass2 = false; } } } }{ const BaseFunction *f = &f21expDomain; double errs[5] = {7.E-1, 3.E-3, 6.E-3, 4.E-5, 4.E-6 }; double transform_a[2] = { 3.0, -3.0 }; double transform_b[2] = { 4.0, 2.0 }; for(int i=0; i<5; i++){ grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), i, TasGrid::type_iptotal, TasGrid::rule_clenshawcurtis); grid.setDomainTransform(transform_a, transform_b); TestResults R = getError(f, grid, type_integration); if (R.error>errs[i]){ cout << "Using clenshaw-curtis rule" << endl; cout << "Failed domain transform test for " << f->getDescription() << " error = " << R.error << " expected: " << errs[i] << endl; pass2 = false; } } }{ const BaseFunction *f = &f21expDomain; double errs[5] = {7.E-1, 7.E-3, 3.E-5, 6.E-8, 7.E-11 }; double transform_a[2] = { 3.0, -3.0 }; double transform_b[2] = { 4.0, 2.0 }; for(int i=0; i<5; i++){ grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), i, TasGrid::type_iptotal, TasGrid::rule_gausslegendre); grid.setDomainTransform(transform_a, transform_b); TestResults R = getError(f, grid, type_integration); if (R.error>errs[i]){ cout << "Using gauss-legendre rule" << endl; cout << "Failed domain transform test for " << f->getDescription() << " error = " << R.error << " expected: " << errs[i] << endl; pass2 = false; } } }{ const BaseFunction *f = &f21expDomain; double errs[5] = {7.E-1, 4.E-1, 4.E-3, 8.E-4, 7.E-7 }; double transform_a[2] = { 3.0, -3.0 }; double transform_b[2] = { 4.0, 2.0 }; for(int i=0; i<5; i++){ grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), i, 2, TasGrid::rule_localp); grid.setDomainTransform(transform_a, transform_b); TestResults R = getError(f, grid, type_integration); if (R.error>errs[i]){ cout << "Using localp rule" << endl; cout << "Failed domain transform test for " << f->getDescription() << " error = " << R.error << " expected: " << errs[i] << endl; pass2 = false; } } }{ const BaseFunction *f = &f21coscos; double errs[5] = { 5.E-2, 7.E-3, 9.E-4, 1.E-13 }; double transform_a[2] = { -1.0, -1.0 }; // canonical domain of Fourier grid is [0,1] double transform_b[2] = { 1.0, 1.0 }; for(int i=0; i<3; i++){ // keeping depth low until we implement an FFT algorithm grid.makeFourierGrid(f->getNumInputs(), f->getNumOutputs(), i+3, TasGrid::type_level); grid.setDomainTransform(transform_a, transform_b); TestResults R = getError(f, grid, type_integration); if (R.error>errs[i]){ cout << "Using fourier rule" << endl; cout << "Failed domain transform test for " << f->getDescription() << " error = " << R.error << " expected: " << errs[i] << endl; pass2 = false; } } } cout << " Domain transformed" << setw(15) << ((pass2) ? "Pass" : "FAIL") << endl; bool pass3 = true; { TasmanianSparseGrid gridc; const BaseFunction *f = &f21conformal; std::vector asin_conformal = {4, 4}; for(int l=0; l<6; l++){ grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), l+2, TasGrid::type_level, TasGrid::rule_clenshawcurtis); gridc.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), l+2, TasGrid::type_level, TasGrid::rule_clenshawcurtis); gridc.setConformalTransformASIN(asin_conformal); auto needed_points = grid.getNeededPoints(); int num_needed = grid.getNumNeeded(); TestResults R1 = getError(f, grid, type_internal_interpolation); TestResults R2 = getError(f, gridc, type_internal_interpolation); if (R1.num_points != R2.num_points){ cout << "Failed in number of points for conformal mapping and clenshaw-curtis rule" << endl; pass3 = false; } if (R1.error < R2.error){ cout << "Failed in error for conformal mapping and clenshaw-curtis rule" << endl; cout << " standard error = " << R1.error << endl; cout << " conformal error = " << R2.error << endl; pass3 = false; } double y1, y2, y_true; grid.integrate(&y1); gridc.integrate(&y2); f->getIntegral(&y_true); if (std::abs(y1 - y_true) < std::abs(y2 - y_true)){ cout << "Failed in error for conformal mapping and clenshaw-curtis rule" << endl; cout << " standard error = " << std::abs(y1 - y_true) << endl; cout << " conformal error = " << std::abs(y2 - y_true) << endl; pass3 = false; } auto loaded_points = grid.getLoadedPoints(); for(int j=0; jgetNumInputs(); j++){ if (std::abs(needed_points[j] - loaded_points[j]) > Maths::num_tol){ cout << "Mismatch between needed and loaded points" << endl; pass2 = false; } } } }{ TasmanianSparseGrid gridc; const BaseFunction *f = &f21conformal; std::vector asin_conformal = { 4, 4 }; for(int l=0; l<1; l++){ grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), l+5, TasGrid::type_iptotal, TasGrid::rule_gausspatterson); gridc.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), l+5, TasGrid::type_iptotal, TasGrid::rule_gausspatterson); gridc.setConformalTransformASIN(asin_conformal); TestResults R1 = getError(f, grid, type_integration); TestResults R2 = getError(f, gridc, type_integration); if (R1.num_points != R2.num_points){ cout << "Failed in number of points for conformal mapping and gauss-patterson rule" << endl; pass3 = false; } if (R1.error < R2.error){ cout << "Failed in error for conformal mapping and gauss-patterson rule" << endl; cout << " standard error = " << R1.error << endl; cout << " conformal error = " << R2.error << endl; pass3 = false; } R1 = getError(f, grid, type_integration); R2 = getError(f, gridc, type_integration); if (R1.error < R2.error){ cout << "Failed in error for conformal mapping and gauss-patterson rule (integration)" << endl; cout << " standard error = " << R1.error << endl; cout << " conformal error = " << R2.error << endl; pass3 = false; } } }{ TasmanianSparseGrid gridc; const BaseFunction *f = &f21conformal; std::vector asin_conformal = { 4, 4 }; for(int l=0; l<5; l++){ grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), l+4, 3, TasGrid::rule_localp); gridc.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), l+4, 3, TasGrid::rule_localp); gridc.setConformalTransformASIN(asin_conformal); TestResults R1 = getError(f, grid, type_internal_interpolation); TestResults R2 = getError(f, gridc, type_internal_interpolation); if (R1.num_points != R2.num_points){ cout << "Failed in number of points for conformal mapping and local polynomial rule" << endl; pass3 = false; } if (R1.error < R2.error){ cout << "Failed in error for conformal mapping and local polynomial rule" << endl; cout << " standard error = " << R1.error << endl; cout << " conformal error = " << R2.error << endl; pass3 = false; } R1 = getError(f, grid, type_integration); R2 = getError(f, gridc, type_integration); if (R1.error < R2.error){ cout << "Failed in error for conformal mapping and local polynomial rule (integration)" << endl; cout << " standard error = " << R1.error << endl; cout << " conformal error = " << R2.error << endl; pass3 = false; } } } cout << " Domain conformal" << setw(15) << ((pass3) ? "Pass" : "FAIL") << endl; bool pass4 = true; { std::vector lower{-2.0, -0.5}, upper{3.0, 1.5}; int const num_samples = 1000; for(int t=0; t<3; t++){ if (t == 0) grid.makeLocalPolynomialGrid(2, 1, 6, 1, rule_localp); if (t == 1) grid.makeWaveletGrid(2, 1, 4, 1); if (t == 2) grid.makeWaveletGrid(2, 1, 4, 3); grid.setDomainTransform(lower, upper); std::vector xrand = genRandom(num_samples, lower, upper); std::vector points = grid.getPoints(); std::vector support = grid.getHierarchicalSupport(); std::vector basis = grid.evaluateHierarchicalFunctions(xrand); // check if points fall outside of the support, then the corresponding basis must be zero for(int s=0; s support[2*i]) || (std::abs( points[2*i+1] - xrand[2*s+1] ) > support[2*i+1])){ if (std::abs(basis[s * grid.getNumPoints() + i]) > Maths::num_tol){ cout << " Failed support test: point (" << points[2*i] << ", " << points[2*i+1] << "), support = (" << support[2*i] << ", " << support[2*i+1] << "), test_point = (" << xrand[2*s] << ", " << xrand[2*s+1] << "), basis = " << basis[s * grid.getNumPoints() + i] << "\n"; pass4 = false; } } } } } grid.makeGlobalGrid(2, 1, 0, type_level, rule_fejer2); std::vector support = grid.getHierarchicalSupport(); if ((support.size() != 2) || (support[0] != 2.0) || (support[1] != 2.0)){ cout << "Failed support test for Global grids.\n"; pass4 = false; } } cout << " Domain support" << setw(15) << ((pass4) ? "Pass" : "FAIL") << endl; return (pass1 && pass2 && pass3 && pass4); } bool ExternalTester::testAcceleration(const BaseFunction *f, TasmanianSparseGrid &grid) const{ int dims = f->getNumInputs(); int outs = f->getNumOutputs(); loadValues(f, grid); int num_x = 256; // for batched evaluations std::vector x = genRandom(num_x, dims); std::vector test_y, baseline_y(outs * num_x); for(int i=0; i acc = {accel_none, accel_cpu_blas, accel_gpu_cublas, accel_gpu_cuda, accel_gpu_magma}; int testGpuID = beginTestGPUID(); size_t c = 0; while(c < acc.size()){ if (c > 1) grid.enableAcceleration(acc[c], testGpuID); // gpu test else grid.enableAcceleration(acc[c]); // test the HIP - CUDA aliases if (grid.getAccelerationType() == accel_gpu_cublas && grid.getAccelerationType() != accel_gpu_rocblas) throw std::runtime_error("failed to acknowledge the accel_gpu_cublas - accel_gpu_rocblas alias"); if (grid.getAccelerationType() == accel_gpu_cuda && grid.getAccelerationType() != accel_gpu_hip) throw std::runtime_error("failed to acknowledge the accel_gpu_cuda - accel_gpu_hip alias"); //grid.printStats(); if (!testAccEval(x, baseline_y, num_x, Maths::num_tol, grid, "accelerated batch")) pass = false; // skips grids that don't have CUDA kernels if (canUseCudaKernels(grid)) if (!testAccEval(x, baseline_y, num_x, 5.E-5, grid, "accelerated batch")) pass = false; #ifdef Tasmanian_ENABLE_GPU if ((grid.getAccelerationType() == accel_gpu_cuda) && !(grid.isWavelet() && grid.getOrder() == 3)){ if (!testDenseGPU(x, baseline_y, num_x, Maths::num_tol, grid, "GPU evaluate")) pass = false; if (!testDenseGPU(x, baseline_y, num_x, 5.E-5, grid, "GPU evaluate")) pass = false; } #endif if (!testAccEval(x, baseline_y, 16, Maths::num_tol, grid, "accelerated fast")) pass = false; if (canUseCudaKernels(grid)) if (!testAccEval(x, baseline_y, 16, 5.E-5, grid, "accelerated fast")) pass = false; if (!pass){ cout << "Failed Batch/Fast evaluation for acceleration c = " << c << " gpuID = " << testGpuID << endl; cout << " -- for function: " << f->getDescription() << endl; } if (c > 1){ // gpu test testGpuID++; if (testGpuID >= endTestGPUID()){ testGpuID = beginTestGPUID(); c++; } }else{ c++; } } return pass; } bool ExternalTester::testGpuCaching() const{ bool pass = true; #ifdef Tasmanian_ENABLE_GPU int const num_samples = 30; std::vector refx = genRandom(num_samples, 2); // using only 30 samples int gpu_id_first = beginTestGPUID(); int gpu_id_last = endTestGPUID(); for(int gpu = gpu_id_first; gpu < gpu_id_last; gpu++){ // test each active CUDA device for(int t=0; t<5; t++){ // test each grid type TasmanianSparseGrid grid = [&]()->TasmanianSparseGrid{ switch(t){ default: case 0: return makeGlobalGrid(2, 1, 3, type_level, rule_clenshawcurtis); case 1: return makeSequenceGrid(2, 1, 5, type_level, rule_leja); case 2: return makeFourierGrid(2, 1, 2, type_level); case 3: return makeLocalPolynomialGrid(2, 1, 3, 1, rule_localp); case 4: return makeWaveletGrid(2, 1, 2, 1); } }(); if (grid.isFourier()) grid.setDomainTransform({-1.0, -1.0}, {1.0, 1.0}); grid.setGPUID(gpu); TasGrid::AccelerationMeta::setDefaultGpuDevice(gpu); for(int run : std::vector{0, 1}){ // do two runs switching devices and grids in-between loadValues(&f21nx2, grid); grid.enableAcceleration(accel_none); std::vector refy; grid.evaluateBatch(refx, refy); grid.enableAcceleration(accel_gpu_cuda); if (!testAccEval(refx, refy, num_samples, Maths::num_tol, grid, "caching batch")) pass = false; if (!testAccEval(refx, refy, num_samples, 5.E-5, grid, "caching batch")) pass = false; if (run == 0){ // setting refinement will change the grid forcing the cache data-structures // to reset when the new values are loaded if (grid.isLocalPolynomial() || grid.isWavelet()) grid.setSurplusRefinement(1.E-4, refine_classic, -1); else grid.setAnisotropicRefinement(type_iptotal, 5, -1); } } } } #endif return pass; } bool ExternalTester::testGPU2GPUevaluations() const{ #ifdef Tasmanian_ENABLE_GPU // check back basis evaluations, x and result both sit on the GPU (using CUDA acceleration) TasGrid::TasmanianSparseGrid grid; int num_tests = 9; int dims = 3; TasGrid::TypeOneDRule pwp_rule[9] = {TasGrid::rule_localp, TasGrid::rule_localp0, TasGrid::rule_semilocalp, TasGrid::rule_localpb, TasGrid::rule_localp, TasGrid::rule_localp0, TasGrid::rule_semilocalp, TasGrid::rule_localpb, TasGrid::rule_localp}; int order[9] = {1, 1, 1, 1, 2, 2, 2, 2, 0}; std::vector a = {3.0, 4.0, -10.0}, b = {5.0, 7.0, 2.0}; bool pass = true; int gpu_index_first = beginTestGPUID(); int gpu_end_gpus = endTestGPUID(); for(int t=0; t xt = genRandom(nump, a, b); // Dense version: std::vector y_true_dense; grid.evaluateHierarchicalFunctions(xt, y_true_dense); // grid.printStats(); // cout << "Memory requirements = " << (grid.getNumPoints() * nump * 8) / (1024 * 1024) << "MB" << endl; std::vector pntr, indx; std::vector vals; grid.evaluateSparseHierarchicalFunctions(xt, pntr, indx, vals); for(int gpuID=gpu_index_first; gpuID < gpu_end_gpus; gpuID++){ // Dense test bool dense_pass = true; grid.enableAcceleration(TasGrid::accel_gpu_cuda); grid.setGPUID(gpuID); TasGrid::AccelerationMeta::setDefaultGpuDevice(gpuID); if (!testDenseGPU(xt, y_true_dense, nump, Maths::num_tol, grid, "GPU basis evaluations")) dense_pass = false; if (!testDenseGPU(xt, y_true_dense, nump, (order[t] == 2) ? 1.E-4 : 5.E-5, grid, "GPU basis evaluations")) dense_pass = false; pass = pass && dense_pass; // Sparse test bool sparse_pass = true; grid.enableAcceleration(TasGrid::accel_gpu_cuda); grid.setGPUID(gpuID); if (!testHBasisGPUSparse(xt, pntr, indx, vals, Maths::num_tol, grid, "GPU sparse basis evaluations")) sparse_pass = false; if (!testHBasisGPUSparse(xt, pntr, indx, vals, (order[t] == 2) ? 1.E-4 : 5.E-5, grid, "GPU sparse basis evaluations")) sparse_pass = false; pass = pass && sparse_pass; } } // Sequence, Global, Wavelet, Fourier Grid evaluations of the basis functions for(int t=0; t<6; t++){ int numx = 2020; auto reset_grid = [&]()->void{ switch(t){ case 0: grid.makeSequenceGrid(dims, 0, 20, type_level, rule_rleja); break; case 1: grid.makeWaveletGrid(dims, 0, 3, 1); break; case 2: grid.makeGlobalGrid(dims, 0, 6, type_level, rule_clenshawcurtis); break; case 3: grid.makeGlobalGrid(dims, 0, 5, type_level, rule_clenshawcurtis0); break; case 4: grid.makeGlobalGrid(dims, 0, 10, type_level, rule_chebyshev); break; case 5: grid.makeFourierGrid(dims, 0, 5, type_level); grid.setDomainTransform(a, b); break; } }; reset_grid(); // Fourier grids use a domain transform to test the non-standard [0,1] -> [a,b] cuda transform // the standard [-1, 1] -> [a, b] is covered in the local polynomial case std::vector cpux = (grid.isFourier()) ? genRandom(numx, a, b) : genRandom(numx, dims); //cout << "Memory requirements = " << (grid.getNumPoints() * numx * 8) / (1024 * 1024) << "MB" << endl; std::vector truey; grid.evaluateHierarchicalFunctions(cpux, truey); for(int gpuID=gpu_index_first; gpuID < gpu_end_gpus; gpuID++){ reset_grid(); TasGrid::AccelerationMeta::setDefaultGpuDevice(gpuID); grid.enableAcceleration(TasGrid::accel_gpu_cuda); grid.setGPUID(gpuID); if (!testDenseGPU(cpux, truey, numx, Maths::num_tol, grid, "GPU basis evaluations")) pass = false; if (!testDenseGPU(cpux, truey, numx, (grid.isFourier()) ? 2.E-4 : 5.E-5, grid, "GPU basis evaluations")) pass = false; } } return pass; #else return true; #endif // Tasmanian_ENABLE_GPU } bool ExternalTester::testAcceleratedLoadValues(TasGrid::TypeOneDRule rule) const{ const BaseFunction *f = &f21expsincos; TasmanianSparseGrid grid_acc, grid_ref; bool pass = true; int gstart = beginTestGPUID(); int gend = endTestGPUID(); for(int g = gstart; g < gend; g++){ if (rule == rule_wavelet){ grid_acc.makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), 2, 1); grid_ref.makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), 2, 1); }else if (rule == rule_fourier){ grid_acc.makeFourierGrid(f->getNumInputs(), f->getNumOutputs(), 4, type_iptotal, {2, 1}); grid_ref.makeFourierGrid(f->getNumInputs(), f->getNumOutputs(), 4, type_iptotal, {2, 1}); }else if (OneDimensionalMeta::isLocalPolynomial(rule)){ grid_acc.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 4, 1, rule); grid_ref.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), 4, 1, rule); }else if (OneDimensionalMeta::isSequence(rule)){ grid_acc.makeSequenceGrid(f->getNumInputs(), f->getNumOutputs(), 6, type_iptotal, rule, {2, 1}); grid_ref.makeSequenceGrid(f->getNumInputs(), f->getNumOutputs(), 6, type_iptotal, rule, {2, 1}); }else{ grid_acc.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 6, type_iptotal, rule, {2, 1}); grid_ref.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 6, type_iptotal, rule, {2, 1}); } grid_acc.enableAcceleration(accel_gpu_cublas); grid_acc.setGPUID(g); loadValues(f, grid_acc); loadValues(f, grid_ref); int num_coeffs = grid_acc.getNumOutputs() * grid_acc.getNumPoints(); if (rule == rule_fourier) num_coeffs *= 2; if (grid_acc.getNumLoaded() != grid_ref.getNumLoaded()){ cout << "ERROR: accelerated loadNeededPoints() loaded wrong number of points." << endl; grid_acc.printStats(); return false; } if (!testPass(err1(wrap_array(grid_acc.getHierarchicalCoefficients(), num_coeffs), wrap_array(grid_ref.getHierarchicalCoefficients(), num_coeffs)), Maths::num_tol, "accelerated loadNeededPoints()")){ cout << "Failed for " << OneDimensionalMeta::getHumanString(rule) << " at gpu: " << g << endl; grid_acc.printStats(); pass = false; } } return pass; } bool ExternalTester::testAllAcceleration() const{ const BaseFunction *f = &f23Kexpsincos; const BaseFunction *f1out = &f21expsincos; TasmanianSparseGrid grid; bool pass = true; int wsecond = 28, wthird = 15; grid.makeGlobalGrid(f->getNumInputs(), f->getNumOutputs(), 5, TasGrid::type_level, TasGrid::rule_clenshawcurtis); pass = pass && testAcceleration(f, grid); grid.makeGlobalGrid(f1out->getNumInputs(), f1out->getNumOutputs(), 5, TasGrid::type_level, TasGrid::rule_clenshawcurtis); pass = pass && testAcceleration(f1out, grid); if (pass){ if (verbose) cout << " Accelerated" << setw(wsecond) << "global" << setw(wthird) << "Pass" << endl; }else{ cout << " Accelerated" << setw(wsecond) << "global" << setw(wthird) << "FAIL" << endl; } grid.makeSequenceGrid(f->getNumInputs(), f->getNumOutputs(), 5, TasGrid::type_level, TasGrid::rule_leja); pass = pass && testAcceleration(f, grid); grid.makeSequenceGrid(f1out->getNumInputs(), f1out->getNumOutputs(), 5, TasGrid::type_level, TasGrid::rule_leja); pass = pass && testAcceleration(f1out, grid); if (pass){ if (verbose) cout << " Accelerated" << setw(wsecond) << "sequence" << setw(wthird) << "Pass" << endl; }else{ cout << " Accelerated" << setw(wsecond) << "sequence" << setw(wthird) << "FAIL" << endl; } // for the purpose of testing CUDA evaluations, test all three localp rules vs orders 0, 1, and 2 // for order 0, regardless of the selected rule, thegrid should switch to localp TasGrid::TypeOneDRule pwp_rule[4] = {TasGrid::rule_localp, TasGrid::rule_localp0, TasGrid::rule_semilocalp, TasGrid::rule_localpb}; for(int t=0; t<12; t++){ grid.makeLocalPolynomialGrid(f->getNumInputs(), f->getNumOutputs(), ((t / 4 == 0) ? 5 : 6), (t / 4), pwp_rule[t % 4]); pass = pass && testAcceleration(f, grid); } // test cusparse sparse mat times dense vec used in accel_type cuda, also try both sparse and dense flavors grid.makeLocalPolynomialGrid(f21nx2.getNumInputs(), f21nx2.getNumOutputs(), 5, 1, TasGrid::rule_localp); grid.favorSparseAcceleration(true); pass = pass && testAcceleration(&f21nx2, grid); grid.makeLocalPolynomialGrid(f1out->getNumInputs(), f1out->getNumOutputs(), 5, 2, TasGrid::rule_semilocalp); grid.favorSparseAcceleration(false); pass = pass && testAcceleration(f1out, grid); if (pass){ if (verbose) cout << " Accelerated" << setw(wsecond) << "local polynomial" << setw(wthird) << "Pass" << endl; }else{ cout << " Accelerated" << setw(wsecond) << "local polynomial" << setw(wthird) << "FAIL" << endl; } grid.makeFourierGrid(f->getNumInputs(), f->getNumOutputs(), 4, TasGrid::type_level); pass = pass && testAcceleration(f, grid); grid.makeFourierGrid(f1out->getNumInputs(), f1out->getNumOutputs(), 4, TasGrid::type_level); pass = pass && testAcceleration(f1out, grid); if (pass){ if (verbose) cout << " Accelerated" << setw(wsecond) << "fourier" << setw(wthird) << "Pass" << endl; }else{ cout << " Accelerated" << setw(wsecond) << "fourier" << setw(wthird) << "FAIL" << endl; } grid.makeWaveletGrid(f->getNumInputs(), f->getNumOutputs(), 2, 3); pass = pass && testAcceleration(f, grid); grid.makeWaveletGrid(f1out->getNumInputs(), f1out->getNumOutputs(), 4, 1); pass = pass && testAcceleration(f1out, grid); if (pass){ if (verbose) cout << " Accelerated" << setw(wsecond) << "wavelet" << setw(wthird) << "Pass" << endl; }else{ cout << " Accelerated" << setw(wsecond) << "wavelet" << setw(wthird) << "FAIL" << endl; } pass = pass && testGpuCaching(); if (pass){ if (verbose) cout << " Accelerated" << setw(wsecond) << "caching" << setw(wthird) << "Pass" << endl; }else{ cout << " Accelerated" << setw(wsecond) << "caching" << setw(wthird) << "FAIL" << endl; } #ifdef Tasmanian_ENABLE_GPU pass = pass && testGPU2GPUevaluations(); if (pass){ if (verbose) cout << " Accelerated" << setw(wsecond) << "gpu-to-gpu" << setw(wthird) << "Pass" << endl; }else{ cout << " Accelerated" << setw(wsecond) << "gpu-to-gpu" << setw(wthird) << "FAIL" << endl; } #else if (verbose) cout << " Accelerated" << setw(wsecond) << "gpu-to-gpu" << setw(wthird) << "Skipped (needs Tasmanian_ENABLE_CUDA=ON)" << endl; #endif // Tasmanian_ENABLE_GPU #ifdef Tasmanian_ENABLE_GPU pass = pass && testAcceleratedLoadValues(rule_clenshawcurtis) && testAcceleratedLoadValues(rule_rleja) && testAcceleratedLoadValues(rule_localp) && testAcceleratedLoadValues(rule_fourier) && testAcceleratedLoadValues(rule_wavelet); if (pass){ if (verbose) cout << " Accelerated" << setw(wsecond) << "load-values" << setw(wthird) << "Pass" << endl; }else{ cout << " Accelerated" << setw(wsecond) << "load-values" << setw(wthird) << "FAIL" << endl; } #else if (verbose) cout << " Accelerated" << setw(wsecond) << "load-values" << setw(wthird) << "Skipped (needs Tasmanian_ENABLE_CUDA=ON)" << endl; #endif cout << " Acceleration all" << setw(15) << ((pass) ? "Pass" : "FAIL") << endl; return pass; } void ExternalTester::debugTest(){ cout << "Debug Test (callable from the CMake build folder)" << endl; cout << "Put testing code here and call with ./SparseGrids/gridtester debug" << endl; } void ExternalTester::debugTestII(){ cout << "Debug Test II (callable from the CMake build folder)" << endl; cout << "Put testing code here and call with ./SparseGrids/gridtester db" << endl; } #endif TASMANIAN-8.1/SparseGrids/gridtestExternalTests.hpp000066400000000000000000000176371470551176200222350ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASGRID_TESTER_HPP #define __TASGRID_TESTER_HPP #include "tasgridLogs.hpp" #include "gridtestCLICommon.hpp" #include "gridtestTestFunctions.hpp" struct TestResults{ double error; int num_points; }; /*! * \internal * \brief Enumerated list of different types of tests within each sparse grid test. * * \endinternal */ enum TestType{ //! \brief Test correctness of integrating with the weights generated by getQuadratureWeights(). type_integration, //! \brief Test correctness of interpolating with the weights generated by getInterpolationWeights(). type_nodal_interpolation, //! \brief Test correctness of differentiating with the weights generated by getDerivativeWeights(). type_nodal_differentiation, //! \brief Test correctness of the evaluate() method. type_internal_interpolation, //! \brief Test correctness of the differentiate() method. type_internal_differentiation }; /*! * \internal * \brief Enumerated list of all individual sparse grid ctests. * * \endinternal */ enum TestList{ //! \brief Perform all tests. test_all, //! \brief Test consistency in the results of all acceleration types. test_acceleration, //! \brief Test correctness of domain transforms and quadrature weight scaling. test_domain, //! \brief Test various refinement strategies. test_refinement, //! \brief Test correctness of global grid algorithms. test_global, //! \brief Test correctness of local polynomial grid algorithms. test_local, //! \brief Test correctness of wavelet grids. test_wavelet, //! \brief Test correctness of Fourier grids. test_fourier, //! \brief This is not a test, indicates an error in parsing CLI arguments. test_none }; class ExternalTester{ public: ExternalTester(int in_num_mc = 1); ~ExternalTester(); void resetRandomSeed(); void setVerbose(bool new_verbose); void setGPUID(int gpu_id); //! \brief Converts the string to a TestList, returns \b test_none if not compatible. static TestList hasTest(std::string const &s); bool Test(TestList test) const; bool testGlobalRule(const BaseFunction *f, TasGrid::TypeOneDRule rule, const int *anisotropic, double alpha, double beta, const std::vector &tests, const int depths[], const double tols[]) const; bool performGlobalTest(TasGrid::TypeOneDRule rule) const; bool performGaussTransfromTest(TasGrid::TypeOneDRule rule) const; bool testLocalPolynomialRule(const BaseFunction *f, TasGrid::TypeOneDRule rule, const int depths[], const double tols[]) const; bool testLocalWaveletRule(const BaseFunction *f, const int depths[], const double tols[], bool flavor) const; bool testSurplusRefinement(const BaseFunction *f, TasmanianSparseGrid &grid, double tol, TypeRefinement rtype, const int np[], const double errs[], int max_iter ) const; bool testAnisotropicRefinement(const BaseFunction *f, TasmanianSparseGrid &grid, TypeDepth type, int min_growth, const int np[], const double errs[], int max_iter ) const; bool testDynamicRefinement(const BaseFunction *f, TasmanianSparseGrid &grid, TypeDepth type, double tolerance, TypeRefinement reftype, const std::vector &np, const std::vector &errs) const; bool testAcceleration(const BaseFunction *f, TasmanianSparseGrid &grid) const; bool testGpuCaching() const; bool testGPU2GPUevaluations() const; bool testAcceleratedLoadValues(TasGrid::TypeOneDRule rule) const; TestResults getError(const BaseFunction *f, TasGrid::TasmanianSparseGrid &grid, TestType type, std::vector const &x = std::vector()) const; bool testAllGlobal() const; bool testAllPWLocal() const; bool testAllWavelet() const; bool testAllFourier() const; bool testAllRefinement() const; bool testAllDomain() const; bool testAllAcceleration() const; void benchmark(int argc, const char **argv); void debugTest(); // call this with -test debug void debugTestII(); // call this with -test debug static const char* findGaussPattersonTable(); static const char* testName(TestType type); int beginTestGPUID() const { // DPC++ uses only one GPU, either the one provided by the CLI // or the one picked by the default_selector_v, i.e., gpuid == -1 #ifdef Tasmanian_ENABLE_DPCPP return gpuid; #else return (gpuid == -1) ? 0 : gpuid; #endif } int endTestGPUID() const { #ifdef Tasmanian_ENABLE_DPCPP return gpuid+1; #else return (gpuid == -1) ? TasmanianSparseGrid::getNumGPUs() : gpuid + 1; #endif } private: int num_mc; bool verbose; int gpuid; std::vector available_acc; std::vector quad_only, int_only, diff_only, quad_int, quad_diff, int_diff, all_test_types; OneOneP0 f11p0; OneOneP3 f11p3; TwoOneExpNX2 f21nx2; TwoOneCos f21cos; TwoOneSinSin f21sinsin; TwoOneCosCos f21coscos; TwoOneExpSinCos f21expsincos; TwoOneSinCosAxis f21sincosaxis; TwoTwoSinCos f22sincos; TwoOneDivisionAnisotropic f21aniso; TwoOne1DCurved f21curved; TwoOneExpm40 f21sharp; TwoOneConstGC1 f21constGC1; TwoOneConstGC2 f21constGC2; TwoOneConstGG f21constGG; TwoOneConstGJ f21constGJ; TwoOneConstGGL f21constGGL; TwoOneConstGH f21constGH; TwoOneENX2aniso f21nx2aniso; TwoTwoExpAsym f22asym; TwoOneExpShiftedDomain f21expDomain; TwoOneConformalOne f21conformal; SixteenOneActive3 f16active3; Two3KExpSinCos f23Kexpsincos; TwoOneC1C2Periodic f21c1c2periodic; }; #endif TASMANIAN-8.1/SparseGrids/gridtestTestFunctions.cpp000066400000000000000000000661541470551176200222310ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_TASGRID_FUNCTIONS_CPP #define __TASMANIAN_TASGRID_FUNCTIONS_CPP #include "gridtestTestFunctions.hpp" #include "TasmanianSparseGrid.hpp" using TasGrid::Maths::pi; BaseFunction::BaseFunction(){} BaseFunction::~BaseFunction(){} OneOneP0::OneOneP0(){} OneOneP0::~OneOneP0(){} int OneOneP0::getNumInputs() const{ return 1; } int OneOneP0::getNumOutputs() const{ return 1; } const char* OneOneP0::getDescription() const{ return "f(x) = 1"; } void OneOneP0::eval(const double*, double y[]) const{ y[0] = 1.0; } void OneOneP0::getIntegral(double y[]) const{ y[0] = 2.0; } void OneOneP0::getDerivative(const double*, double y[]) const{ y[0] = 0.0; } OneOneP3::OneOneP3(){} OneOneP3::~OneOneP3(){} int OneOneP3::getNumInputs() const{ return 1; } int OneOneP3::getNumOutputs() const{ return 1; } const char* OneOneP3::getDescription() const{ return "f(x) = x^3 + 2 x^2 + x + 3"; } void OneOneP3::eval(const double x[], double y[]) const{ y[0] = x[0]*x[0]*x[0] + 2.0*x[0]*x[0] + x[0] + 3.0; } void OneOneP3::getIntegral(double y[]) const{ y[0] = 22.0/3.0; } void OneOneP3::getDerivative(const double x[], double y[]) const{ y[0] = 3.0*x[0]*x[0] + 4.0*x[0] + 1.0; } OneOneP4::OneOneP4(){} OneOneP4::~OneOneP4(){} int OneOneP4::getNumInputs() const{ return 1; } int OneOneP4::getNumOutputs() const{ return 1; } const char* OneOneP4::getDescription() const{ return "f(x) = 0.5 x^4 + x^3 + 2 x^2 + x + 3"; } void OneOneP4::eval(const double x[], double y[]) const{ y[0] = 0.5*x[0]*x[0]*x[0]*x[0] + x[0]*x[0]*x[0] + 2.0*x[0]*x[0] + x[0] + 3.0; } void OneOneP4::getIntegral(double y[]) const{ y[0] = 226.0/30.0; } void OneOneP4::getDerivative(const double x[], double y[]) const{ y[0] = 2.0*x[0]*x[0]*x[0] + 3.0*x[0]*x[0] + 4.0*x[0] + 1.0; } OneOneExpMX::OneOneExpMX(){} OneOneExpMX::~OneOneExpMX(){} int OneOneExpMX::getNumInputs() const{ return 1; } int OneOneExpMX::getNumOutputs() const{ return 1; } const char* OneOneExpMX::getDescription() const{ return "f(x) = exp(-x^2)"; } void OneOneExpMX::eval(const double x[], double y[]) const{ y[0] = std::exp(- x[0] * x[0]); } void OneOneExpMX::getIntegral(double y[]) const{ y[0] = 1.493648265624854; } void OneOneExpMX::getDerivative(const double x[], double y[]) const{ y[0] = -2.0*x[0]*std::exp(-x[0]*x[0]); } TwoOneP4::TwoOneP4(){} TwoOneP4::~TwoOneP4(){} int TwoOneP4::getNumInputs() const{ return 2; } int TwoOneP4::getNumOutputs() const{ return 1; } const char* TwoOneP4::getDescription() const{ return "f(x,y) = x^4 + x^3 y + x^2 y^2 + x^1 y^3 + y^4"; } void TwoOneP4::eval(const double x[], double y[]) const{ y[0] = x[0]*x[0]*x[0]*x[0] + x[0]*x[0]*x[0]*x[1] + x[0]*x[0]*x[1]*x[1] + x[0]*x[1]*x[1]*x[1] + x[1]*x[1]*x[1]*x[1]; } void TwoOneP4::getIntegral(double y[]) const{ y[0] = 92.0/45.0; } void TwoOneP4::getDerivative(const double x[], double y[]) const{ y[0] = 4.0*x[0]*x[0]*x[0] + 3.0*x[0]*x[0]*x[1] + 2.0*x[0]*x[1]*x[1] + x[1]*x[1]*x[1]; y[1] = x[0]*x[0]*x[0] + 2.0*x[0]*x[0]*x[1] + 3.0*x[0]*x[1]*x[1] + 4.0*x[1]*x[1]*x[1]; } TwoOneP5::TwoOneP5(){} TwoOneP5::~TwoOneP5(){} int TwoOneP5::getNumInputs() const{ return 2; } int TwoOneP5::getNumOutputs() const{ return 1; } const char* TwoOneP5::getDescription() const{ return "f(x,y) = x^5 + x^4 y + x^3 y^2 + x^2 y^3 + x y^4 + y^5"; } void TwoOneP5::eval(const double x[], double y[]) const{ y[0] = x[0]*x[0]*x[0]*x[0]*x[0] + x[0]*x[0]*x[0]*x[0]*x[1] + x[0]*x[0]*x[0]*x[1]*x[1] + x[0]*x[0]*x[1]*x[1]*x[1] + x[0]*x[1]*x[1]*x[1]*x[1] + x[1]*x[1]*x[1]*x[1]*x[1]; } void TwoOneP5::getIntegral(double y[]) const{ y[0] = 0.0; } void TwoOneP5::getDerivative(const double x[], double y[]) const{ y[0] = 5.0*x[0]*x[0]*x[0]*x[0] + 4.0*x[0]*x[0]*x[0]*x[1] + 3.0*x[0]*x[0]*x[1]*x[1] + 2.0*x[0]*x[1]*x[1]*x[1] + x[1]*x[1]*x[1]*x[1]; y[1] = x[0]*x[0]*x[0]*x[0] + 2.0*x[0]*x[0]*x[0]*x[1] + 3.0*x[0]*x[0]*x[1]*x[1] + 4.0*x[0]*x[1]*x[1]*x[1] + 5.0*x[1]*x[1]*x[1]*x[1]; } TwoOneExpNX2::TwoOneExpNX2(){} TwoOneExpNX2::~TwoOneExpNX2(){} int TwoOneExpNX2::getNumInputs() const{ return 2; } int TwoOneExpNX2::getNumOutputs() const{ return 1; } const char* TwoOneExpNX2::getDescription() const{ return "f(x,y) = exp(-x^2 - y^2)"; } void TwoOneExpNX2::eval(const double x[], double y[]) const{ y[0] = std::exp(-x[0]*x[0] - x[1]*x[1]); } void TwoOneExpNX2::getIntegral(double y[]) const{ y[0] = 2.230985141404134; } void TwoOneExpNX2::getDerivative(const double x[], double y[]) const{ y[0] = -2.0*x[0]*std::exp(-x[0]*x[0] - x[1]*x[1]); y[1] = -2.0*x[1]*std::exp(-x[0]*x[0] - x[1]*x[1]); } ThreeOneExpNX2::ThreeOneExpNX2(){} ThreeOneExpNX2::~ThreeOneExpNX2(){} int ThreeOneExpNX2::getNumInputs() const{ return 3; } int ThreeOneExpNX2::getNumOutputs() const{ return 1; } const char* ThreeOneExpNX2::getDescription() const{ return "f(x,y,z) = exp(-x^2 - y^2 - z^2)"; } void ThreeOneExpNX2::eval(const double x[], double y[]) const{ y[0] = std::exp(-x[0]*x[0] - x[1]*x[1] - x[2]*x[2]); } void ThreeOneExpNX2::getIntegral(double y[]) const{ y[0] = 3.332307087; } void ThreeOneExpNX2::getDerivative(const double x[], double y[]) const{ y[0] = -2.0*x[0]*std::exp(-x[0]*x[0] - x[1]*x[1] - x[2]*x[2]); y[1] = -2.0*x[1]*std::exp(-x[0]*x[0] - x[1]*x[1] - x[2]*x[2]); y[2] = -2.0*x[2]*std::exp(-x[0]*x[0] - x[1]*x[1] - x[2]*x[2]); } TwoOneCos::TwoOneCos(){} TwoOneCos::~TwoOneCos(){} int TwoOneCos::getNumInputs() const{ return 2; } int TwoOneCos::getNumOutputs() const{ return 1; } const char* TwoOneCos::getDescription() const{ return "f(x,y) = cos(-x^2 - y^2 + xy)"; } void TwoOneCos::eval(const double x[], double y[]) const{ y[0] = std::cos(-x[0]*x[0] - x[1]*x[1] + x[0]*x[1]); } void TwoOneCos::getIntegral(double y[]) const{ y[0] = 2.8137178748032379; } void TwoOneCos::getDerivative(const double x[], double y[]) const{ y[0] = -(-2.0*x[0]+x[1]) * std::sin(-x[0]*x[0] - x[1]*x[1] + x[0]*x[1]); y[1] = -(-2.0*x[1]+x[0]) * std::sin(-x[0]*x[0] - x[1]*x[1] + x[0]*x[1]); } TwoOneSinSin::TwoOneSinSin(){} TwoOneSinSin::~TwoOneSinSin(){} int TwoOneSinSin::getNumInputs() const{ return 2; } int TwoOneSinSin::getNumOutputs() const{ return 1; } const char* TwoOneSinSin::getDescription() const{ return "f(x,y) = sin(pi * x) sin(pi * y)"; } void TwoOneSinSin::eval(const double x[], double y[]) const{ y[0] = std::sin(pi * x[0]) * std::sin(pi * x[1]); } void TwoOneSinSin::getIntegral(double y[]) const{ y[0] = 0.0; } void TwoOneSinSin::getDerivative(const double x[], double y[]) const{ y[0] = pi * std::cos(pi * x[0]) * std::sin(pi * x[1]); y[1] = pi * std::sin(pi * x[0]) * std::cos(pi * x[1]); } TwoOneCosCos::TwoOneCosCos(){} TwoOneCosCos::~TwoOneCosCos(){} int TwoOneCosCos::getNumInputs() const{ return 2; } int TwoOneCosCos::getNumOutputs() const{ return 1; } const char* TwoOneCosCos::getDescription() const{ return "f(x,y) = cos(pi/2 * x) cos(pi/2 * y)"; } void TwoOneCosCos::eval(const double x[], double y[]) const{ y[0] = std::cos(0.5 * pi * x[0]) * std::cos(0.5 * pi * x[1]); } void TwoOneCosCos::getIntegral(double y[]) const{ y[0] = 16.0 / (pi * pi); } void TwoOneCosCos::getDerivative(const double x[], double y[]) const{ y[0] = -0.5*pi * std::sin(0.5 * pi * x[0]) * std::cos(0.5 * pi * x[1]); y[1] = -0.5*pi * std::cos(0.5 * pi * x[0]) * std::sin(0.5 * pi * x[1]); } TwoOneExpSinCos::TwoOneExpSinCos() {} TwoOneExpSinCos::~TwoOneExpSinCos() {} int TwoOneExpSinCos::getNumInputs() const{ return 2; } int TwoOneExpSinCos::getNumOutputs() const{ return 1; } const char* TwoOneExpSinCos::getDescription() const{ return "f(x,y) = exp(sin(2*pi*x) + cos(2*pi*y)) on [0,1]^2 "; } void TwoOneExpSinCos::eval(const double x[], double y[]) const{ y[0] = std::exp(std::sin(2*pi*x[0])+std::cos(2*pi*x[1])); } void TwoOneExpSinCos::getIntegral(double y[]) const{ y[0] = 1.6029228068079633 * 4.0; } void TwoOneExpSinCos::getDerivative(const double x[], double y[]) const{ y[0] = 2*pi * std::cos(2*pi*x[0]) * std::exp(std::sin(2*pi*x[0])+std::cos(2*pi*x[1])); y[1] = -2*pi * std::sin(2*pi*x[1]) * std::exp(std::sin(2*pi*x[0])+std::cos(2*pi*x[1])); } TwoOneSinCosAxis::TwoOneSinCosAxis() {} TwoOneSinCosAxis::~TwoOneSinCosAxis() {} int TwoOneSinCosAxis::getNumInputs() const{ return 2; } int TwoOneSinCosAxis::getNumOutputs() const{ return 1; } const char* TwoOneSinCosAxis::getDescription() const{ return "f(x,y) = 1.0 + sin(pi * (x + y)) * cos(pi * (x - y)) on [-1,1]^2 "; } void TwoOneSinCosAxis::eval(const double x[], double y[]) const{ y[0] = 1.0 + std::sin(pi*(x[0] + x[1])) * std::cos(pi*(x[0] - x[1])); } void TwoOneSinCosAxis::getIntegral(double y[]) const{ y[0] = 4.0; } void TwoOneSinCosAxis::getDerivative(const double x[], double y[]) const{ y[0] = pi * std::cos(pi*(x[0] + x[1])) * std::cos(pi*(x[0] - x[1])) - pi * std::sin(pi*(x[0] + x[1])) * std::sin(pi*(x[0] - x[1])); y[1] = pi * std::cos(pi*(x[0] + x[1])) * std::cos(pi*(x[0] - x[1])) + pi * std::sin(pi*(x[0] + x[1])) * std::sin(pi*(x[0] - x[1])); } TwoTwoSinCos::TwoTwoSinCos() {} TwoTwoSinCos::~TwoTwoSinCos() {} int TwoTwoSinCos::getNumInputs() const{ return 2; } int TwoTwoSinCos::getNumOutputs() const{ return 2; } const char* TwoTwoSinCos::getDescription() const{ return "f(x,y) = [sin(2*pi*x)cos(4*pi*y), x^2*cos(2*pi*x)]"; } void TwoTwoSinCos::eval(const double x[], double y[]) const{ y[0] = std::sin(2*pi*x[0])*std::cos(4*pi*x[1]); y[1] = x[0]*x[0]*cos(2*pi*x[0]); } void TwoTwoSinCos::getIntegral(double y[]) const{ y[0] = 0.0; y[1] = 1.0 / (2.0 * pi * pi); } void TwoTwoSinCos::getDerivative(const double x[], double y[]) const{ y[0] = 2.0*pi * std::cos(2.0*pi*x[0])*std::cos(4*pi*x[1]); y[1] = -4.0*pi * std::sin(2*pi*x[0])*std::sin(4*pi*x[1]); y[2] = 2.0*x[0]*std::cos(2*pi*x[0]) - 2.0*pi*x[0]*x[0]*std::sin(2*pi*x[0]); y[3] = 0.0; } TwoOneExpm40::TwoOneExpm40(){} TwoOneExpm40::~TwoOneExpm40(){} int TwoOneExpm40::getNumInputs() const{ return 2; } int TwoOneExpm40::getNumOutputs() const{ return 1; } const char* TwoOneExpm40::getDescription() const{ return "f(x,y) = 1.0 / (1.0 + exp(-40.0 * (sqrt(x^2 + y^2) - 0.4)))"; } void TwoOneExpm40::eval(const double x[], double y[]) const{ y[0] = 1.0 / (1.0 + exp(-40.0 * (std::sqrt(x[0]*x[0] + x[1]*x[1]) - 0.4))); } void TwoOneExpm40::getIntegral(double y[]) const{ y[0] = 0.0; } void TwoOneExpm40::getDerivative(const double x[], double y[]) const{ double nrm = std::sqrt(x[0]*x[0] + x[1]*x[1]); double a0 = -40.0 * nrm - 0.4; double a1 = 40 * exp(a0) / ((exp(a0) + 1) * (exp(a0) + 1) * nrm); y[0] = x[0] * a1; y[1] = x[1] * a1; } FiveOneExpSum::FiveOneExpSum(){} FiveOneExpSum::~FiveOneExpSum(){} int FiveOneExpSum::getNumInputs() const{ return 5; } int FiveOneExpSum::getNumOutputs() const{ return 1; } const char* FiveOneExpSum::getDescription() const{ return "f(y_i) = 1 + exp(-2 - 0.4 * sum(x_i))"; } void FiveOneExpSum::eval(const double x[], double y[]) const{ y[0] = 1.0 + std::exp(-2.0 -0.4 * (x[0]+x[1]+x[2]+x[3]+x[4])); } void FiveOneExpSum::getIntegral(double y[]) const{ y[0] = 32.0 + std::exp(-2.0) * pow((1.0/0.4) * (exp(0.4) - std::exp(-0.4)), 5.0); } void FiveOneExpSum::getDerivative(const double x[], double y[]) const{ double a0 = std::exp(-2.0 -0.4 * (x[0]+x[1]+x[2]+x[3]+x[4])); for (int i=0; i<5; i++) y[i] = -0.4 * a0; } SixOneExpSum::SixOneExpSum(){} SixOneExpSum::~SixOneExpSum(){} int SixOneExpSum::getNumInputs() const{ return 6; } int SixOneExpSum::getNumOutputs() const{ return 1; } const char* SixOneExpSum::getDescription() const{ return "f(y_i) = exp(-sum(x_i^2))"; } void SixOneExpSum::eval(const double x[], double y[]) const{ y[0] = exp(-x[0]*x[0]-x[1]*x[1]-x[2]*x[2]-x[3]*x[3]-x[4]*x[4]-x[5]*x[5]); } void SixOneExpSum::getIntegral(double y[]) const{ y[0] = 1.110427052269093e+01; } void SixOneExpSum::getDerivative(const double x[], double y[]) const{ double a0 = exp(-x[0]*x[0]-x[1]*x[1]-x[2]*x[2]-x[3]*x[3]-x[4]*x[4]-x[5]*x[5]); for (int i=0; i<6; i++) y[i] = -2.0 * x[i] * a0; } EightOneCosSum::EightOneCosSum(){} EightOneCosSum::~EightOneCosSum(){} int EightOneCosSum::getNumInputs() const{ return 8; } int EightOneCosSum::getNumOutputs() const{ return 1; } const char* EightOneCosSum::getDescription() const{ return "f(y_i) = cos(sum(x_i))"; } void EightOneCosSum::eval(const double x[], double y[]) const{ y[0] = std::cos(x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6]+x[7]); } void EightOneCosSum::getIntegral(double y[]) const{ y[0] = 6.435067827089459e+01; } void EightOneCosSum::getDerivative(const double x[], double y[]) const{ double a0 = -std::sin(x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6]+x[7]); for (int i=0; i<8; i++) y[i] = a0; } ThreeOneUnitBall::ThreeOneUnitBall(){} ThreeOneUnitBall::~ThreeOneUnitBall(){} int ThreeOneUnitBall::getNumInputs() const{ return 3; } int ThreeOneUnitBall::getNumOutputs() const{ return 1; } const char* ThreeOneUnitBall::getDescription() const{ return "f(x_i) = 1 if ||x||_{2} < 1, 0 otherwise"; } void ThreeOneUnitBall::eval(const double x[], double y[]) const{ if ((x[0]*x[0]+x[1]*x[1]+x[2]*x[2]) <= 1.0){ y[0] = 1.0; }else{ y[0] = 0.0; } } void ThreeOneUnitBall::getIntegral(double y[]) const{ y[0] = (4.0/3.0) * pi; } void ThreeOneUnitBall::getDerivative(const double*, double y[]) const { y[0] = 0.0; y[1] = 0.0; y[2] = 0.0; } TwoOneConstGC1::TwoOneConstGC1(){} TwoOneConstGC1::~TwoOneConstGC1(){} int TwoOneConstGC1::getNumInputs() const{ return 2; } int TwoOneConstGC1::getNumOutputs() const{ return 1; } const char* TwoOneConstGC1::getDescription() const{ return "f(x,y) = exp(x+y), integrated against 1.0 / (sqrt(1 - x*x) * sqrt(1 - y*y))"; } void TwoOneConstGC1::eval(const double x[], double y[]) const{ y[0] = std::exp(x[0]+x[1]); } void TwoOneConstGC1::getIntegral(double y[]) const{ y[0] = 15.820213988678377; } void TwoOneConstGC1::getDerivative(const double x[], double y[]) const{ y[0] = std::exp(x[0]+x[1]); y[1] = std::exp(x[0]+x[1]); } TwoOneConstGC2::TwoOneConstGC2(){} TwoOneConstGC2::~TwoOneConstGC2(){} int TwoOneConstGC2::getNumInputs() const{ return 2; } int TwoOneConstGC2::getNumOutputs() const{ return 1; } const char* TwoOneConstGC2::getDescription() const{ return "f(x,y) = exp(x+y), integrated against (sqrt(1 - x*x) * sqrt(1 - y*y))"; } void TwoOneConstGC2::eval(const double x[], double y[]) const{ y[0] = std::exp(x[0] + x[1]); } void TwoOneConstGC2::getIntegral(double y[]) const{ y[0] = 3.152399146392550; } void TwoOneConstGC2::getDerivative(const double x[], double y[]) const{ y[0] = std::exp(x[0]+x[1]); y[1] = std::exp(x[0]+x[1]); } TwoOneConstGG::TwoOneConstGG(){} TwoOneConstGG::~TwoOneConstGG(){} int TwoOneConstGG::getNumInputs() const{ return 2; } int TwoOneConstGG::getNumOutputs() const{ return 1; } const char* TwoOneConstGG::getDescription() const{ return "f(x,y) = exp(x+y), integrated against (1 - x*x)^0.3 * (1 - y*y)^0.3"; } void TwoOneConstGG::eval(const double x[], double y[]) const{ y[0] = std::exp(x[0] + x[1]); } void TwoOneConstGG::getIntegral(double y[]) const{ y[0] = 1.955951775017494*1.955951775017494; } void TwoOneConstGG::getDerivative(const double x[], double y[]) const{ y[0] = std::exp(x[0]+x[1]); y[1] = std::exp(x[0]+x[1]); } TwoOneConstGJ::TwoOneConstGJ(){} TwoOneConstGJ::~TwoOneConstGJ(){} int TwoOneConstGJ::getNumInputs() const{ return 2; } int TwoOneConstGJ::getNumOutputs() const{ return 1; } const char* TwoOneConstGJ::getDescription() const{ return "f(x,y) = exp(x+y), integrated against (1 - x)^0.3 * (1 - x)^0.7 * (1 - y)^0.3 * (1 - y)^0.7"; } void TwoOneConstGJ::eval(const double x[], double y[]) const{ y[0] = std::exp(x[0] + x[1]); } void TwoOneConstGJ::getIntegral(double y[]) const{ y[0] = 2.093562254087821*2.093562254087821; } void TwoOneConstGJ::getDerivative(const double x[], double y[]) const{ y[0] = std::exp(x[0]+x[1]); y[1] = std::exp(x[0]+x[1]); } TwoOneConstGGL::TwoOneConstGGL(){} TwoOneConstGGL::~TwoOneConstGGL(){} int TwoOneConstGGL::getNumInputs() const{ return 2; } int TwoOneConstGGL::getNumOutputs() const{ return 1; } const char* TwoOneConstGGL::getDescription() const{ return "f(x,y) = exp(-x-y), integrated against (x)^0.3 * exp(-x) * (y)^0.3 * exp(-y)"; } void TwoOneConstGGL::eval(const double x[], double y[]) const{ y[0] = std::exp(-x[0]-x[1]); } void TwoOneConstGGL::getIntegral(double y[]) const{ y[0] = 0.364486361867136*0.364486361867136; } void TwoOneConstGGL::getDerivative(const double x[], double y[]) const{ y[0] = -std::exp(-x[0]-x[1]); y[1] = -std::exp(-x[0]-x[1]); } TwoOneConstGH::TwoOneConstGH(){} TwoOneConstGH::~TwoOneConstGH(){} int TwoOneConstGH::getNumInputs() const{ return 2; } int TwoOneConstGH::getNumOutputs() const{ return 1; } const char* TwoOneConstGH::getDescription() const{ return "f(x,y) = exp(-x-y), integrated against |x|^0.3 * exp(-x^2) * |y|^0.3 * exp(-y^2)"; } void TwoOneConstGH::eval(const double x[], double y[]) const{ y[0] = std::exp(-x[0]-x[1]); } void TwoOneConstGH::getIntegral(double y[]) const{ y[0] = 1.902578389458335*1.902578389458335; } void TwoOneConstGH::getDerivative(const double x[], double y[]) const{ y[0] = -std::exp(-x[0]-x[1]); y[1] = -std::exp(-x[0]-x[1]); } TwoOneENX2aniso::TwoOneENX2aniso(){} TwoOneENX2aniso::~TwoOneENX2aniso(){} int TwoOneENX2aniso::getNumInputs() const{ return 2; } int TwoOneENX2aniso::getNumOutputs() const{ return 1; } const char* TwoOneENX2aniso::getDescription() const{ return "f(x,y) = exp(-x^2 -0.1*y^2)"; } void TwoOneENX2aniso::eval(const double x[], double y[]) const{ y[0] = std::exp(-x[0]*x[0] -0.1*x[1]*x[1]); } void TwoOneENX2aniso::getIntegral(double y[]) const{ y[0] = 2.890637511323280e+00; } void TwoOneENX2aniso::getDerivative(const double x[], double y[]) const{ y[0] = -2.0*x[0] * std::exp(-x[0]*x[0] -0.1*x[1]*x[1]); y[1] = -0.2*x[1] * std::exp(-x[0]*x[0] -0.1*x[1]*x[1]); } TwoTwoExpAsym::TwoTwoExpAsym(){} TwoTwoExpAsym::~TwoTwoExpAsym(){} int TwoTwoExpAsym::getNumInputs() const{ return 2; } int TwoTwoExpAsym::getNumOutputs() const{ return 2; } const char* TwoTwoExpAsym::getDescription() const{ return "f(x,y) = {exp(-(x-0.1)^2 - (y-0.2)^2), exp(-(x-0.3)^2 - (y-0.4)^2)}"; } void TwoTwoExpAsym::eval(const double x[], double y[]) const{ y[0] = std::exp(-(x[0] - 0.1) * (x[0] - 0.1) - (x[1] - 0.2) * (x[1] - 0.2)); y[1] = std::exp(-(x[0] - 0.3) * (x[0] - 0.3) - (x[1] - 0.4) * (x[1] - 0.4)); } void TwoTwoExpAsym::getIntegral(double y[]) const{ y[0] = 2.1765637578800963e+00; y[1] = 1.9699377347041238e+00; } void TwoTwoExpAsym::getDerivative(const double x[], double y[]) const{ double a0 = std::exp(-(x[0] - 0.1) * (x[0] - 0.1) - (x[1] - 0.2) * (x[1] - 0.2)); y[0] = -2.0 * (x[0] - 0.1) * a0; y[1] = -2.0 * (x[1] - 0.2) * a0; double a1 = std::exp(-(x[0] - 0.3) * (x[0] - 0.3) - (x[1] - 0.4) * (x[1] - 0.4)); y[2] = -2.0 * (x[0] - 0.3) * a1; y[3] = -2.0 * (x[1] - 0.4) * a1; } SixteenOneActive3::SixteenOneActive3(){} SixteenOneActive3::~SixteenOneActive3(){} int SixteenOneActive3::getNumInputs() const{ return 16; } int SixteenOneActive3::getNumOutputs() const{ return 1; } const char* SixteenOneActive3::getDescription() const{ return "f(x,y) = x[2] * sin(x[3] + x[15])"; } void SixteenOneActive3::eval(const double x[], double y[]) const{ y[0] = x[2] * std::sin(x[3] + x[15]); } void SixteenOneActive3::getIntegral(double y[]) const{ y[0] = 0.0; } void SixteenOneActive3::getDerivative(const double x[], double y[]) const{ for (int i=0; i<16; i++) y[i] = 0.0; y[2] = std::sin(x[3] + x[15]); y[3] = x[2] * std::cos(x[3] + x[15]); y[15] = x[2] * std::cos(x[3] + x[15]); } TwoOneDivisionAnisotropic::TwoOneDivisionAnisotropic(){} TwoOneDivisionAnisotropic::~TwoOneDivisionAnisotropic(){} int TwoOneDivisionAnisotropic::getNumInputs() const{ return 2; } int TwoOneDivisionAnisotropic::getNumOutputs() const{ return 1; } const char* TwoOneDivisionAnisotropic::getDescription() const{ return "f(x,y) = 1.0 / ((x[0] - 1.1) * (x[0] + 1.1) * (x[1] - 2) * (x[1] + 2))"; } void TwoOneDivisionAnisotropic::eval(const double x[], double y[]) const{ y[0] = 1.0 / ((x[0] - 1.1) * (x[0] + 1.1) * (x[1] - 2) * (x[1] + 2)); } void TwoOneDivisionAnisotropic::getIntegral(double y[]) const{ y[0] = 1.520340801458519; } void TwoOneDivisionAnisotropic::getDerivative(const double x[], double y[]) const{ double a0 = ((x[0] - 1.1) * (x[0] + 1.1) * (x[1] - 2.0) * (x[1] + 2.0)); y[0] = -2.0 * x[0] * (x[1] - 2.0) * (x[1] + 2.0) / (a0 * a0); y[1] = -2.0 * x[1] * (x[0] - 1.1) * (x[0] + 1.1) / (a0 * a0); } TwoOne1DCurved::TwoOne1DCurved(){} TwoOne1DCurved::~TwoOne1DCurved(){} int TwoOne1DCurved::getNumInputs() const{ return 2; } int TwoOne1DCurved::getNumOutputs() const{ return 1; } const char* TwoOne1DCurved::getDescription() const{ return "f(x,y) = exp(-x[0]) + exp(x[1])"; } void TwoOne1DCurved::eval(const double x[], double y[]) const{ y[0] = std::exp(-x[0]) + std::exp(x[1]); } void TwoOne1DCurved::getIntegral(double y[]) const{ y[0] = 5.524391382167265; } void TwoOne1DCurved::getDerivative(const double x[], double y[]) const{ y[0] = -std::exp(-x[0]); y[1] = std::exp(x[1]); } TwoOneExpShiftedDomain::TwoOneExpShiftedDomain(){} TwoOneExpShiftedDomain::~TwoOneExpShiftedDomain(){} int TwoOneExpShiftedDomain::getNumInputs() const{ return 2; } int TwoOneExpShiftedDomain::getNumOutputs() const{ return 1; } const char* TwoOneExpShiftedDomain::getDescription() const{ return "f(x,y) = exp(x[0] / 3.0 + x[1] / 5.0)"; } void TwoOneExpShiftedDomain::eval(const double x[], double y[]) const{ y[0] = std::exp(x[0]/3.0 + x[1]/5.0); } void TwoOneExpShiftedDomain::getIntegral(double y[]) const{ y[0] = 15.0*(std::exp(26.0/15.0) - std::exp(11.0/15.0) - std::exp(7.0/5.0) + std::exp(2.0/5.0)); } void TwoOneExpShiftedDomain::getDerivative(const double x[], double y[]) const{ double a0 = std::exp(x[0]/3.0 + x[1]/5.0); y[0] = 1/3.0 * a0; y[1] = 1/5.0 * a0; } OneOneConformalOne::OneOneConformalOne(){} OneOneConformalOne::~OneOneConformalOne(){} int OneOneConformalOne::getNumInputs() const{ return 1; } int OneOneConformalOne::getNumOutputs() const{ return 1; } const char* OneOneConformalOne::getDescription() const{ return "f(x) = 1 / (1 + 5x^2)"; } void OneOneConformalOne::eval(const double x[], double y[]) const{ y[0] = 1.0 / (1.0 + 5.0 * x[0]*x[0]); } void OneOneConformalOne::getIntegral(double y[]) const{ y[0] = 1.028825601981092; } void OneOneConformalOne::getDerivative(const double x[], double y[]) const{ double a0 = 1.0 + 5.0 * x[0]*x[0]; y[0] = -10.0 * x[0] / (a0 * a0); } TwoOneConformalOne::TwoOneConformalOne(){} TwoOneConformalOne::~TwoOneConformalOne(){} int TwoOneConformalOne::getNumInputs() const{ return 2; } int TwoOneConformalOne::getNumOutputs() const{ return 1; } const char* TwoOneConformalOne::getDescription() const{ return "f(x) = 1 / ((1 + 5x^2)*(1 + 5y^2))"; } void TwoOneConformalOne::eval(const double x[], double y[]) const{ y[0] = 1.0 / ((1.0 + 5.0*x[0]*x[0]) * (1.0 + 5.0*x[1]*x[1])); } void TwoOneConformalOne::getIntegral(double y[]) const{ y[0] = 1.028825601981092*1.028825601981092; } void TwoOneConformalOne::getDerivative(const double x[], double y[]) const{ double a0 = (1.0 + 5.0*x[0]*x[0]) * (1.0 + 5.0*x[1]*x[1]); y[0] = -10.0 * x[0] * (1.0 + 5.0 * x[1] * x[1]) / (a0 * a0); y[1] = -10.0 * x[1] * (1.0 + 5.0 * x[0] * x[0]) / (a0 * a0); } Two3KExpSinCos::Two3KExpSinCos(){} Two3KExpSinCos::~Two3KExpSinCos(){} int Two3KExpSinCos::getNumInputs() const{ return 2; } int Two3KExpSinCos::getNumOutputs() const{ return 3072; } const char* Two3KExpSinCos::getDescription() const{ return "f(x) = exp(x+y), 1+sin(x+y), cos(3*x+y)"; } void Two3KExpSinCos::eval(const double x[], double y[]) const{ for(int i=0; i<1025; i++){ y[i] = std::exp(x[0] + x[1]); } for(int i=1025; i<2055; i++){ y[i] = std::sin(x[0] + x[1]) + 1.0; } for(int i=2055; i<3072; i++){ y[i] = std::cos(3.0*x[0] + x[1]); } } void Two3KExpSinCos::getIntegral(double y[]) const{ for(int i=0; i<1025; i++){ y[i] = 1.902578389458335*1.902578389458335; } for(int i=1025; i<2055; i++){ y[i] = 4.0; } for(int i=2055; i<3072; i++){ y[i] = 0.158331189544313; } } void Two3KExpSinCos::getDerivative(const double x[], double y[]) const{ // Row 1 for(int i=0; i<1025; i++){ y[i] = std::exp(x[0] + x[1]); } for(int i=1025; i<2055; i++){ y[i] = std::cos(x[0] + x[1]); } for(int i=2055; i<3072; i++){ y[i] = -3.0 * std::sin(3.0*x[0] + x[1]); } // Row 2 int base = 3072; for(int i=base; i #include "TasmanianSparseGrid.hpp" using std::cout; using std::endl; using namespace TasGrid; template struct wrap_array{ template wrap_array(T *in_raw, U in_num) : raw(in_raw), num(size_t(in_num)){} T *raw; size_t num; size_t size() const{ return num; } T const& operator[](size_t i) const{ return raw[i]; } }; template double err1(size_t num, VectorLike1 const &x, VectorLike2 const &y){ if ((x.size() < num) || (y.size() < num)) throw std::runtime_error("vector size is insufficient"); double err = 0.0; for(size_t i=0; i double err1(VectorLike1 const &x, VectorLike2 const &y){ if (x.size() != y.size()) throw std::runtime_error("vector size mismatch"); return err1(x.size(), x, y); } template std::vector> extractRow(size_t i, std::vector const &pntr, std::vector const &indx, VectorLike const &vals){ std::vector> result; result.reserve(pntr[i+1] - pntr[i]); for(int j=pntr[i]; j(indx[j], vals[j])); return result; } template void sortRow(std::vector> &row){ std::sort(row.begin(), row.end(), [&](std::pair &a, std::pair &b)-> bool{ return a.first < b.first; }); } template double err1_sparse(std::vector const &xpntr, std::vector const &xindx, VectorLike1 const &xvals, std::vector const &ypntr, std::vector const &yindx, VectorLike2 const &yvals){ if (xpntr.size() != ypntr.size()) throw std::runtime_error("mismatch in number of sparse rows"); double err = 0.0; for(size_t i=0; isecond; }else if (iy == yrow.end()){ // read all y, using only x xv = ix++ ->second; yv = 0.0; }else if (ix->first == iy->first){ // index pair match xv = ix++ ->second; yv = iy++ ->second; }else if (ix->first < iy->first){ // y skips an index xv = ix++ ->second; yv = 0.0; }else{ // since sorted, x must have skipped an index xv = 0.0; yv = iy++ ->second; } err = std::max(err, std::abs(xv - yv)); } } return err; } inline bool testPass(double err, double tol, std::string message, TasmanianSparseGrid const &grid = TasmanianSparseGrid()){ if (err > tol){ cout << std::scientific; cout.precision(16); cout << "ERROR: " << message << "\n observed: " << err << " expected: " << tol << "\n"; if (!grid.empty()) grid.printStats(); return false; }else{ return true; } } inline std::vector const& getVector(std::vector const &x, std::vector&, size_t){ return x; } inline std::vector const& getVector(std::vector const &x, std::vector &t, size_t num){ t = std::vector(num); std::transform(x.begin(), x.begin() + num, t.begin(), [](double const&v)->float{ return static_cast(v); }); return t; } struct GridMethodBatch{}; struct GridMethodFast{}; template bool testAccEval(std::vector const &x, std::vector const &y, int numx, double tolerance, TasmanianSparseGrid &grid, std::string message){ std::vector test_y, temp_x; std::vector const &test_x = getVector(x, temp_x, Utils::size_mult(grid.getNumDimensions(), numx)); if (std::is_same::value){ grid.evaluateBatch(test_x, test_y); }else if (std::is_same::value){ test_y = std::vector(Utils::size_mult(numx, grid.getNumOutputs())); Utils::Wrapper2D wx(grid.getNumDimensions(), test_x.data()); Utils::Wrapper2D wy(grid.getNumOutputs(), test_y.data()); for(int i=0; i 2 || grid.getOrder() == -1)) return false; if (grid.isWavelet() && grid.getOrder() == 3) return false; return true; } #ifdef Tasmanian_ENABLE_GPU struct GridMethodHierBasisGPU{}; struct GridMethodEvalBatchGPU{}; template bool testDenseGPU(std::vector const &x, std::vector const &y, int numx, double tolerance, TasmanianSparseGrid const &grid, std::string message){ AccelerationContext const *acceleration = grid.getAccelerationContext(); GpuVector gpux; gpux.load(acceleration, x); GpuVector gpuy(acceleration, ((grid.isFourier() && std::is_same::value) ? 2 : 1) * numx, (std::is_same::value) ? grid.getNumPoints() : grid.getNumOutputs()); if (std::is_same::value){ grid.evaluateBatchGPU(gpux.data(), numx, gpuy.data()); }else if (std::is_same::value){ grid.evaluateHierarchicalFunctionsGPU(gpux.data(), numx, gpuy.data()); } auto cpuy = gpuy.unload(acceleration); return testPass(err1(cpuy, y), tolerance, message, grid); } template bool testHBasisGPUSparse(std::vector const &x, std::vector const &pntr, std::vector const &indx, std::vector const &vals, double tolerance, TasmanianSparseGrid const &grid, std::string message){ if (grid.empty()){ cout << "ERROR: cannot test an empty grid\n"; return false; } AccelerationContext const *acceleration = grid.getAccelerationContext(); GpuVector gpux; gpux.load(acceleration, x); int nump = (int) x.size() / grid.getNumDimensions(); int *gpu_indx = 0, *gpu_pntr = 0, num_nz = 0; T *gpu_vals = 0; grid.evaluateSparseHierarchicalFunctionsGPU(gpux.data(), nump, gpu_pntr, gpu_indx, gpu_vals, num_nz); std::vector cpntr; AccelerationMeta::recvGpuArray(acceleration, nump + 1, gpu_pntr, cpntr); std::vector cindx; AccelerationMeta::recvGpuArray(acceleration, num_nz, gpu_indx, cindx); std::vector cvals; AccelerationMeta::recvGpuArray(acceleration, num_nz, gpu_vals, cvals); AccelerationMeta::delGpuArray(acceleration, gpu_pntr); AccelerationMeta::delGpuArray(acceleration, gpu_indx); AccelerationMeta::delGpuArray(acceleration, gpu_vals); return testPass(err1_sparse(pntr, indx, vals, cpntr, cindx, cvals), tolerance, message, grid); } #endif #endif TASMANIAN-8.1/SparseGrids/gridtestTestInterfaceC.cpp000066400000000000000000000212771470551176200222610ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ extern "C"{ #include "stdio.h" #include "stdlib.h" #include "math.h" #include "TasmanianSparseGrid.h" // The bulk of the C interface is tested through the Python wrapper // The purpose of this function is to test the C header and the few untested functions int testInterfaceC(){ void *grid = tsgConstructTasmanianSparseGrid(); if (tsgGetPoints(grid) != 0){ printf("ERROR: empty grid did not return null pointer on tsgGetPoints()\n"); return 0; } tsgMakeGlobalGrid(grid, 2, 1, 1, "level", "clenshaw-curtis", 0, 0.0, 0.0, 0, 0); int num_points = tsgGetNumPoints(grid); if (num_points != 5){ printf("ERROR: simple Clenshaw-Curtis grid doesn't have 5 points."); return 0; } if (tsgGetLoadedPoints(grid) != 0){ printf("ERROR: empty grid did not return null pointer on tsgGetLoadedPoints()\n"); return 0; } double tpoints[10] = {0.0, 0.0, 0.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 0.0}; double *points = tsgGetPoints(grid); int i, j; for(i=0; i<10; i++) if (fabs(points[i] - tpoints[i]) > 1.E-15){ printf("ERROR: mismatch in points i = %d, expected = %1.16e, actual = %1.16e\n",i,tpoints[i],points[i]); return 0; } free(points); points = tsgGetNeededPoints(grid); for(i=0; i<10; i++) if (fabs(points[i] - tpoints[i]) > 1.E-15){ printf("ERROR: mismatch in needed points i = %d, expected = %1.16e, actual = %1.16e\n",i,tpoints[i],points[i]); return 0; } free(points); double values[5] = {0.0, 1.0, 1.0, 1.0, 1.0}; tsgLoadNeededPoints(grid, values); if (tsgGetNeededPoints(grid) != 0){ printf("ERROR: empty grid did not return null pointer on tsgGetNeededPoints()\n"); return 0; } points = tsgGetLoadedPoints(grid); for(i=0; i<10; i++) if (fabs(points[i] - tpoints[i]) > 1.E-15){ printf("ERROR: mismatch in loaded points i = %d, expected = %1.16e, actual = %1.16e\n",i,tpoints[i],points[i]); return 0; } free(points); double tweights[5] = {4.0/3.0, 2.0/3.0, 2.0/3.0, 2.0/3.0, 2.0/3.0}; double *weights = tsgGetQuadratureWeights(grid); for(i=0; i<5; i++) if (fabs(weights[i] - tweights[i]) > 1.E-15){ printf("ERROR: mismatch quadrature i = %d, expected = %1.16e, actual = %1.16e\n",i,tweights[i],weights[i]); return 0; } free(weights); double x[2] = {0.0, 1.0}; double tiweights[5] = {0.0, 0.0, 1.0, 0.0, 0.0}; weights = tsgGetInterpolationWeights(grid, x); for(i=0; i<5; i++) if (fabs(weights[i] - tiweights[i]) > 1.E-15){ printf("ERROR: mismatch iweights i = %d, expected = %1.16e, actual = %1.16e\n",i,tiweights[i],weights[i]); return 0; } free(weights); int n = tsgGetNumPoints(grid); points = tsgGetPoints(grid); weights = tsgBatchGetInterpolationWeights(grid, points, n); for(i=0; i 1.E-15){ printf("ERROR: mismatch batch iweights i = %d, expected = %1.16e, actual = %1.16e\n",i,expect,weights[i]); return 0; } } } free(weights); free(points); int tcoeffs[4]; tsgEstimateAnisotropicCoefficientsStatic(grid, "ipcurved", 0, tcoeffs); int *coeffs = tsgEstimateAnisotropicCoefficients(grid, "ipcurved", 0, &n); if (n != 4){ printf("ERROR: mismatch in number of anisotropic coefficients\n"); return 0; } for(i=0; i err) err = fabs(external_result[i] - internal_result[i]); if (err > 1.E-13){ printf("ERROR: mismatch in external and internal sparse hierarchical matrix.\n"); return 0; } free(pntr); free(indx); free(vals); free(external_result); free(internal_result); free(model); free(pnts); free(x2); tsgDestructTasmanianSparseGrid(grid); // test global polynomial space grid = tsgConstructTasmanianSparseGrid(); tsgMakeGlobalGrid(grid, 2, 1, 1, "level", "clenshaw-curtis", 0, 0.0, 0.0, 0, 0); int *pspace; int tspace[10] = {0, 0, 0, 1, 0, 2, 1, 0, 2, 0}; tsgGetGlobalPolynomialSpace(grid, 1, &n, &pspace); if (n != 5){ printf("ERROR: mismatch in size of the interpolated polynomial space.\n"); return 0; } for(i=0; i<10; i++) if (pspace[i] != tspace[i]){ printf("ERROR: mismatch in polynomial space i = %d, expected = %d, actual = %d\n",i,tspace[i],pspace[i]); return 0; } free(pspace); tsgDestructTasmanianSparseGrid(grid); grid = tsgConstructTasmanianSparseGrid(); void* grid_copy = tsgConstructTasmanianSparseGrid(); tsgMakeGlobalGrid(grid, 2, 1, 1, "level", "fejer2", 0, 0.0, 0.0, 0, 0); tsgCopyGrid(grid_copy, grid); double *quad1 = tsgGetQuadratureWeights(grid); double *quad2 = tsgGetQuadratureWeights(grid_copy); for(i=0; i 1.E-15){ printf("ERROR: mismatch in quadrature after copy.\n"); return 0; } free(quad1); free(quad2); tsgDestructTasmanianSparseGrid(grid); tsgDestructTasmanianSparseGrid(grid_copy); return 1; } } TASMANIAN-8.1/SparseGrids/gridtestUnitTests.cpp000066400000000000000000001076641470551176200213650ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASGRID_UNIT_TESTS_CPP #define __TASGRID_UNIT_TESTS_CPP #include "gridtestUnitTests.hpp" #include "gridtestExternalTests.hpp" #include "gridtestTestHelpers.hpp" #include "tsgTPLWrappers.hpp" #ifdef Tasmanian_ENABLE_HIP #ifndef __HIP_PLATFORM_HCC__ #define __HIP_PLATFORM_HCC__ #endif #include #include #endif #ifdef Tasmanian_ENABLE_DPCPP #include #endif void gridLoadEN2(TasmanianSparseGrid *grid){ // load points using model exp( - \| x \|^2 ) std::vector points; grid->getNeededPoints(points); int dims = grid->getNumDimensions(); int outs = grid->getNumOutputs(); int nump = grid->getNumNeeded(); std::vector vals(Utils::size_mult(nump, outs)); for(int i=0; iloadNeededPoints(vals); } GridUnitTester::GridUnitTester() : verbose(false){} GridUnitTester::~GridUnitTester(){} void GridUnitTester::setVerbose(bool new_verbose){ verbose = new_verbose; } UnitTests GridUnitTester::hasTest(std::string const &s){ std::map string_to_test = { {"all", unit_all}, {"cover", unit_cover}, {"errors", unit_except}, {"api", unit_api}, {"c", unit_c}, {"lapack", unit_lapack} }; try{ return string_to_test.at(s); }catch(std::out_of_range &){ return unit_none; } } bool GridUnitTester::Test(UnitTests test){ cout << endl << endl; cout << "---------------------------------------------------------------------" << endl; cout << " Tasmanian Sparse Grids Module: Unit Tests" << endl; cout << "---------------------------------------------------------------------" << endl << endl; bool testCover = true; bool testExceptions = true; bool testAPI = true; bool testC = true; bool testLAPACK = true; if ((test == unit_all) || (test == unit_cover)) testCover = testCoverUnimportant(); if ((test == unit_all) || (test == unit_except)) testExceptions = testAllException(); if ((test == unit_all) || (test == unit_api)) testAPI = testAPIconsistency(); if ((test == unit_all) || (test == unit_c)) testC = testCInterface(); if ((test == unit_all) || (test == unit_lapack)) testLAPACK = testLAPACKInterface(); bool pass = testCover && testExceptions && testAPI && testC && testLAPACK; //bool pass = true; cout << endl; if (pass){ cout << "---------------------------------------------------------------------" << endl; cout << " All Unit Tests Completed Successfully" << endl; cout << "---------------------------------------------------------------------" << endl << endl; }else{ cout << "FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL" << endl; cout << " Some Unit Tests Have Failed" << endl; cout << "FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL FAIL" << endl << endl; } return pass; } bool GridUnitTester::testAllException(){ bool pass = true; bool passAll = true; int wfirst = 15, wsecond = 30, wthird = 15; // perform std::invalid_argument tests auto tests = getInvalidArgumentCalls(); int test_count = 0; for(auto &t : tests) try{ test_count++; t(); // run the test cout << "Missed arg exception for test " << test_count << " see GridUnitTester::getInvalidArgumentCalls()" << endl; pass = false; break; }catch(std::invalid_argument &){ //cout << "Got argument error exception on test " << test_count << " with message: " << e.what() << endl; } if (verbose) cout << setw(wfirst) << "Exception" << setw(wsecond) << "std::invalid_argument" << setw(wthird) << ((pass) ? "Pass" : "FAIL") << endl; passAll = passAll && pass; pass = true; // perform std::runtime_error tests tests = getRuntimeErrorCalls(); test_count = 0; for(auto &t : tests) try{ test_count++; t(); cout << "Missed runtime exception for test " << test_count << " see GridUnitTester::getRuntimeErrorCalls()" << endl; pass = false; break; }catch(std::runtime_error &){ //cout << "Got runtime error exception on test " << test_count << " with message: " << e.what() << endl; } if (verbose) cout << setw(wfirst) << "Exception" << setw(wsecond) << "std::runtime_error" << setw(wthird) << ((pass) ? "Pass" : "FAIL") << endl; passAll = passAll && pass; cout << setw(wfirst+1) << "Exceptions" << setw(wsecond-1) << "" << setw(wthird) << ((passAll) ? "Pass" : "FAIL") << endl; return pass; } bool GridUnitTester::doesMatch(const std::vector &a, const std::vector &b, double prec) const{ if (a.size() != b.size()) return false; auto ib = b.begin(); for(auto x : a) if (std::abs(x - *ib++) > prec) return false; return true; } bool GridUnitTester::doesMatch(const std::vector &a, const double b[], double prec) const{ auto ib = b; for(auto x : a) if (std::abs(x - *ib++) > prec) return false; return true; } bool GridUnitTester::doesMatch(const std::vector &a, const int b[]) const{ auto ib = b; for(auto x : a) if (x != *ib++) return false; return true; } bool GridUnitTester::doesMatch(size_t n, double a[], const double b[], double prec) const{ for(size_t i=0; i prec) return false; return true; } bool GridUnitTester::testAPIconsistency(){ bool passAll = true; int wfirst = 15, wsecond = 30, wthird = 15; // test array and vector consistency between the two versions of the API bool pass = true; std::vector vpoints; #ifdef Tasmanian_ENABLE_DPCPP sycl::queue q; // the sycl queue must be declared before the grid so it is deleted after the grid #endif TasmanianSparseGrid grid; grid.makeGlobalGrid(2, 1, 4, type_iptotal, rule_clenshawcurtis); gridLoadEN2(&grid); grid.setAnisotropicRefinement(type_iptotal, 10, 0); if (verbose) cout << setw(wfirst) << "API variation" << setw(wsecond) << "getPoints()" << setw(wthird) << ((pass) ? "Pass" : "FAIL") << endl; passAll = pass && passAll; grid.makeGlobalGrid(2, 1, 1, type_iptotal, rule_rleja); std::vector pindexes(grid.getPointsIndexes(), grid.getPointsIndexes() + 6); std::vector refindexes = {0, 0, 0, 1, 1, 0}; pass = doesMatch(refindexes, pindexes.data()); if (verbose) cout << setw(wfirst) << "API variation" << setw(wsecond) << "getPointsIndexes()" << setw(wthird) << ((pass) ? "Pass" : "FAIL") << endl; passAll = pass && passAll; grid.makeGlobalGrid(2, 1, 4, type_iptotal, rule_clenshawcurtis); gridLoadEN2(&grid); std::vector vy, x = {0.333, -0.333}; double *ay = new double[2]; grid.evaluate(x, vy); grid.evaluate(x.data(), ay); pass = pass && doesMatch(vy, ay); vy.clear(); grid.integrate(vy); grid.integrate(ay); pass = pass && doesMatch(vy, ay); vy.clear(); auto dy = grid.differentiate(x); grid.differentiate(x, vy); grid.differentiate(x.data(), ay); pass = pass && doesMatch(vy, ay); pass = pass && doesMatch(vy, dy); delete[] ay; std::vector vf, vx = {0.333, 0.44, -0.1333, 0.2223}; double *af = new double[grid.getNumPoints() * 2]; grid.evaluateHierarchicalFunctions(vx.data(), 2, af); grid.evaluateHierarchicalFunctions(vx, vf); pass = pass && doesMatch(vf, af); delete[] af; if (verbose) cout << setw(wfirst) << "API variation" << setw(wsecond) << "evaluate/integrate" << setw(wthird) << ((pass) ? "Pass" : "FAIL") << endl; passAll = pass && passAll; std::vector vtransa = {-2.0, 1.0}, vtransb = {1.0, 2.0}; double atransa[2], atransb[2]; grid.setDomainTransform(vtransa, vtransb); grid.getDomainTransform(atransa, atransb); pass = pass && doesMatch(vtransa, atransa) && doesMatch(vtransb, atransb); grid.clearDomainTransform(); grid.getDomainTransform(vtransa, vtransb); if (vtransa.size() + vtransb.size() != 0) pass = false; if (verbose) cout << setw(wfirst) << "API variation" << setw(wsecond) << "domain transform" << setw(wthird) << ((pass) ? "Pass" : "FAIL") << endl; passAll = pass && passAll; int allimits[3] = {1, 2, 3}; grid.makeGlobalGrid(3, 2, 5, type_iptotal, rule_fejer2, 0, 0.0, 0.0, 0, allimits); auto llimits = grid.getLevelLimits(); pass = pass && doesMatch(llimits, allimits) && (llimits.size() == 3); grid.clearLevelLimits(); llimits = grid.getLevelLimits(); if (llimits.size() != 0) pass = false; if (verbose) cout << setw(wfirst) << "API variation" << setw(wsecond) << "level limits" << setw(wthird) << ((pass) ? "Pass" : "FAIL") << endl; passAll = pass && passAll; // test integer-to-enumerate and string-to-enumerate conversion pass = true; std::vector allacc = {accel_none, accel_cpu_blas, accel_gpu_default, accel_gpu_cublas, accel_gpu_cuda, accel_gpu_magma}; for(auto acc : allacc){ if (acc != AccelerationMeta::getIOAccelerationString(AccelerationMeta::getIOAccelerationString(acc))){ cout << "ERROR: mismatch in string to accel conversion: " << AccelerationMeta::getIOAccelerationString(acc) << endl; pass = false; } if (acc != AccelerationMeta::getIOIntAcceleration(AccelerationMeta::getIOAccelerationInt(acc))){ cout << "ERROR: mismatch in string to accel conversion: " << AccelerationMeta::getIOIntAcceleration(acc) << endl; pass = false; } } passAll = pass && passAll; // misc tests pass = true; if (makeEmpty().evaluateSparseHierarchicalFunctionsGetNZ(std::vector(10, 0.33).data(), 10) != 0){ cout << "ERROR: did not evaluate sparse nnz to zero." << endl; pass = false; } if (makeEmpty().getHierarchicalCoefficients() != nullptr){ cout << "ERROR: the hierarchical coefficients of empty should be null." << endl; pass = false; } #ifdef Tasmanian_ENABLE_GPU grid = makeGlobalGrid(2, 1, 4, type_iptotal, rule_clenshawcurtis); // resets the acceleration mode gridLoadEN2(&grid); std::vector baseline_y, test_x = {0.33, 0.33, -0.33, -0.33, -0.66, 0.66}; grid.evaluateBatch(test_x, baseline_y); TasGrid::AccelerationMeta::setDefaultGpuDevice(0); grid.enableAcceleration(accel_gpu_cuda, 0); #ifdef Tasmanian_ENABLE_CUDA if (not TasmanianSparseGrid::isCudaEnabled()) throw std::runtime_error("Ambiguous is CUDA enabled!"); auto manual_handle = TasGrid::AccelerationMeta::createCublasHandle(); grid.setCuBlasHandle(manual_handle); #endif #ifdef Tasmanian_ENABLE_HIP if (not TasmanianSparseGrid::isHipEnabled()) throw std::runtime_error("Ambiguous is HIP enabled!"); rocblas_handle manual_handle; rocblas_create_handle(&manual_handle); grid.setRocBlasHandle(manual_handle); #endif #ifdef Tasmanian_ENABLE_DPCPP if (not TasmanianSparseGrid::isDpcppEnabled()) throw std::runtime_error("Ambiguous is DPC++ enabled!"); grid.setSycleQueue(&q); #endif if (!testDenseGPU(test_x, baseline_y, 3, Maths::num_tol, grid, "GPU evaluate with manual handle")) pass = false; #ifdef Tasmanian_ENABLE_CUDA TasGrid::AccelerationMeta::deleteCublasHandle(manual_handle); #endif #ifdef Tasmanian_ENABLE_HIP rocblas_destroy_handle(manual_handle); #endif #endif passAll = pass && passAll; if ((TasmanianSparseGrid::isCudaEnabled() and TasmanianSparseGrid::isHipEnabled()) or (TasmanianSparseGrid::isCudaEnabled() and TasmanianSparseGrid::isDpcppEnabled()) or (TasmanianSparseGrid::isDpcppEnabled() and TasmanianSparseGrid::isHipEnabled())){ throw std::runtime_error("Ambiguous two GPU backends report as enabled!"); } TasmanianSparseGrid dummy_grid = TasGrid::makeFourierGrid(2, 1, 3, TasGrid::type_level); dummy_grid.enableAcceleration(TasGrid::accel_gpu_cuda); // makes an acceleration engine // the engine is never used and the handles are null, should still destroy properly cout << setw(wfirst+1) << "API variations" << setw(wsecond-1) << "" << setw(wthird) << ((passAll) ? "Pass" : "FAIL") << endl; return passAll; } bool GridUnitTester::testCInterface(){ bool pass = (testInterfaceC() != 0); int wfirst = 15, wsecond = 30, wthird = 15; cout << setw(wfirst+1) << "C interface" << setw(wsecond-1) << "" << setw(wthird) << ((pass) ? "Pass" : "FAIL") << endl; return pass; } bool GridUnitTester::testCoverUnimportant(){ // some code is hard/impractical to test automatically, but untested code shows in coverage reports // this function gives coverage to such special cases to avoid confusion in the report const char *str = TasmanianSparseGrid::getGitCommitHash(); const char *str2 = TasmanianSparseGrid::getCmakeCxxFlags(); str = TasmanianSparseGrid::getCmakeCxxFlags(); if (str[0] != str2[0]){ cout << "ERROR: mismatch in strings in testCoverUnimportant()" << endl; return false; } std::vector rules = {rule_none, rule_clenshawcurtis, rule_clenshawcurtis0, rule_chebyshev, rule_chebyshevodd, rule_gausslegendre, rule_gausslegendreodd, rule_gausspatterson, rule_leja, rule_lejaodd, rule_rleja, rule_rlejadouble2, rule_rlejadouble4, rule_rlejaodd, rule_rlejashifted, rule_rlejashiftedeven, rule_rlejashifteddouble, rule_maxlebesgue, rule_maxlebesgueodd, rule_minlebesgue, rule_minlebesgueodd, rule_mindelta, rule_mindeltaodd, rule_gausschebyshev1, rule_gausschebyshev1odd, rule_gausschebyshev2, rule_gausschebyshev2odd, rule_fejer2, rule_gaussgegenbauer, rule_gaussgegenbauerodd, rule_gaussjacobi, rule_gaussjacobiodd, rule_gausslaguerre, rule_gausslaguerreodd, rule_gausshermite, rule_gausshermiteodd, rule_customtabulated, rule_localp, rule_localp0, rule_semilocalp, rule_localpb, rule_wavelet, rule_fourier}; for(auto r : rules) str = OneDimensionalMeta::getHumanString(r); if (!AccelerationMeta::isAccTypeGPU(accel_gpu_default)){ cout << "ERROR: mismatch in isAccTypeFullMemoryGPU()" << endl; return false; } RuleWavelet rule(1, 10); str = rule.getDescription(); rule.updateOrder(3); str = rule.getDescription(); return true; } std::vector> GridUnitTester::getInvalidArgumentCalls() const{ return std::vector>{ [](void)->void{ auto grid = makeGlobalGrid(0, 1, 3, type_level, rule_gausslegendre); // dimension is 0 }, [](void)->void{ auto grid = makeGlobalGrid(2, -1, 3, type_level, rule_gausslegendre); // output is -1 }, [](void)->void{ auto grid = makeGlobalGrid(2, 2, -1, type_level, rule_rleja); // depth is -1 }, [](void)->void{ auto grid = makeGlobalGrid(2, 2, 1, type_level, rule_localp); // rule is localp }, [](void)->void{ auto grid = makeGlobalGrid(2, 2, 2, type_level, rule_rleja, {3}); // aw is too short }, [](void)->void{ auto grid = makeGlobalGrid(2, 2, 2, type_level, rule_customtabulated); // custom filename is empty }, [](void)->void{ auto grid = makeGlobalGrid(2, 2, 2, type_level, rule_chebyshev, {}, 0.0, 0.0, nullptr, {3}); // level limits is too short }, [](void)->void{ auto grid = makeSequenceGrid(0, 1, 3, type_level, rule_rleja); // dimension is 0 }, [](void)->void{ auto grid = makeSequenceGrid(2, -1, 3, type_level, rule_minlebesgue); // output is -1 }, [](void)->void{ auto grid = makeSequenceGrid(2, 2, -1, type_level, rule_rleja); // depth is -1 }, [](void)->void{ auto grid = makeSequenceGrid(2, 1, 3, type_level, rule_localp); // localp is not a sequence rule }, [](void)->void{ auto grid = makeSequenceGrid(2, 2, 2, type_level, rule_rleja, {3}); // aw is too short }, [](void)->void{ auto grid = makeSequenceGrid(2, 2, 2, type_level, rule_chebyshev, {}, {3}); // level limits is too short }, [](void)->void{ auto grid = makeLocalPolynomialGrid(0, 1, 3, 3, rule_localp); // 0 is not valid dimensions }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, -1, 3, 2, rule_localp); // -1 is not valid outputs }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, -1, 2, rule_localp); // -1 is not valid depth }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3, -2, rule_localp); // -2 is not a valid order }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3, 2, rule_mindelta); // mindelta is not a local rule }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3, 1, rule_localp, {3}); // level limits is too short }, [](void)->void{ auto grid = makeWaveletGrid(0, 1, 3, 1); // 0 is not a valid dimensions }, [](void)->void{ auto grid = makeWaveletGrid(2, -1, 3, 1); // -1 is not a valid outputs }, [](void)->void{ auto grid = makeWaveletGrid(2, 1, -3, 1); // -3 is not a valid depth }, [](void)->void{ auto grid = makeWaveletGrid(2, 1, 3, 2); // 2 is not a valid order for wavelets }, [](void)->void{ auto grid = makeWaveletGrid(2, 1, 3, 1, {3}); // level limits is too short }, [](void)->void{ auto grid = makeFourierGrid(0, 1, 3, type_level); // dimension is 0 }, [](void)->void{ auto grid = makeFourierGrid(2, -1, 3, type_level); // output is -1 }, [](void)->void{ auto grid = makeFourierGrid(2, 2, -1, type_level); // depth is -1 }, [](void)->void{ auto grid = makeFourierGrid(2, 2, 2, type_level, {3}); // aw is too short }, [](void)->void{ auto grid = makeFourierGrid(2, 2, 2, type_level, {}, {3}); // level limits is too short }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); grid.updateGlobalGrid(-1, type_level); // depth is negative }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); grid.updateGlobalGrid(3, type_level, {3}); // aw is too small }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); grid.updateGlobalGrid(3, type_level, {}, {3}); // ll is too small }, [](void)->void{ auto grid = makeSequenceGrid(2, 1, 3, type_level, rule_rleja); grid.updateSequenceGrid(-1, type_level); // depth is negative }, [](void)->void{ auto grid = makeSequenceGrid(2, 1, 3, type_level, rule_rleja); grid.updateSequenceGrid(3, type_level, {3}); // aw is too small }, [](void)->void{ auto grid = makeSequenceGrid(2, 1, 3, type_level, rule_rleja); grid.updateSequenceGrid(3, type_level, {}, {3}); // ll is too small }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); grid.setAnisotropicRefinement(type_iptotal, -1, 0, {1, 2}); // min_growth is negative }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); gridLoadEN2(&grid); grid.setAnisotropicRefinement(type_iptotal, 1, 2, {}); // output out of range }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); gridLoadEN2(&grid); grid.setAnisotropicRefinement(type_iptotal, 1, 0, {3}); // ll is too small }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); gridLoadEN2(&grid); auto w = grid.estimateAnisotropicCoefficients(type_iptotal, 2); // output out of range }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); gridLoadEN2(&grid); grid.setSurplusRefinement(0.01, 2); // output out of range }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); gridLoadEN2(&grid); grid.setSurplusRefinement(0.01, 0, {3}); // ll is too small }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); gridLoadEN2(&grid); grid.setSurplusRefinement(-0.1, 0); // tolerance is negative }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); gridLoadEN2(&grid); grid.setSurplusRefinement(0.01, refine_classic, 2); // output out of range }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); gridLoadEN2(&grid); grid.setSurplusRefinement(0.01, refine_classic, 0, {3}); // ll is too small }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); gridLoadEN2(&grid); grid.setSurplusRefinement(-0.1, refine_classic, 0); // tolerance is negative }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); gridLoadEN2(&grid); grid.setSurplusRefinement(-0.1, refine_classic, 0, {3, 2}, {3.0, 3.0}); //scale too small }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); grid.setDomainTransform({1.0}, {3.0, 4.0}); // a is too small }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); grid.setDomainTransform({1.0, 2.0}, {4.0}); // b is too small }, [](void)->void{ CustomTabulated custom; custom.read("phantom.file"); }, }; } std::vector> GridUnitTester::getRuntimeErrorCalls() const{ return std::vector>{ [](void)->void{ TasmanianSparseGrid grid; grid.updateGlobalGrid(2, type_level); // grid not initialized }, [](void)->void{ TasmanianSparseGrid grid; grid.updateSequenceGrid(2, type_level); // grid not initialized }, [](void)->void{ std::vector v; auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); grid.getInterpolationWeights({0.33}, v); // wrong size of x }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 2, type_level, rule_rleja); grid.loadNeededPoints({0.33, 0.22}); // wrong size of loaded data }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 1, type_level, rule_clenshawcurtis); grid.loadNeededPoints({0.33, 0.22, 0.22, 0.22, 0.33}); grid.loadNeededPoints({0.33, 0.22}); // wrong size of loaded data (when overwriting) }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 1, type_level, rule_clenshawcurtis); grid.loadNeededPoints({0.33, 0.22, 0.22, 0.22, 0.33}); std::vector y, x = {0.44f, 0.44f}; grid.evaluateBatch(x, y); // either CUDA not enabled or not available at all }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 0, type_level, rule_fejer2); double a[2], b[2]; grid.getDomainTransform(a, b); // cannot call getDomainTransform(array overload) without transform }, [](void)->void{ TasmanianSparseGrid grid; grid.setAnisotropicRefinement(type_iptotal, 1, 0, 0); // grid not made }, [](void)->void{ TasmanianSparseGrid grid; grid.setAnisotropicRefinement(type_iptotal, 1, 0, {}); // grid not made }, [](void)->void{ auto grid = makeGlobalGrid(2, 0, 3, type_level, rule_rleja); grid.setAnisotropicRefinement(type_iptotal, 1, 0, {}); // no outputs }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); grid.setAnisotropicRefinement(type_iptotal, 1, 0, {}); // no loaded values }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_chebyshev); gridLoadEN2(&grid); grid.setAnisotropicRefinement(type_iptotal, 1, 0, {}); // rule non-nested }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); gridLoadEN2(&grid); grid.setAnisotropicRefinement(type_iptotal, 1, 0,{}); // grid is localp }, [](void)->void{ TasmanianSparseGrid grid; auto w = grid.estimateAnisotropicCoefficients(type_iptotal, 1); // grid not made }, [](void)->void{ auto grid = makeGlobalGrid(2, 0, 3, type_level, rule_rleja); auto w = grid.estimateAnisotropicCoefficients(type_iptotal, 0); // no outputs }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); auto w = grid.estimateAnisotropicCoefficients(type_iptotal, 0); // no loaded values }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_chebyshev); gridLoadEN2(&grid); auto w = grid.estimateAnisotropicCoefficients(type_iptotal, 0); // rule non-nested }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); gridLoadEN2(&grid); auto w = grid.estimateAnisotropicCoefficients(type_iptotal, 0); // grid is localp }, [](void)->void{ TasmanianSparseGrid grid; grid.setSurplusRefinement(0.01, 0, 0); // grid not init }, [](void)->void{ TasmanianSparseGrid grid; grid.setSurplusRefinement(0.01, 0, {}); // grid not init }, [](void)->void{ auto grid = makeGlobalGrid(2, 0, 3, type_level, rule_rleja); grid.setSurplusRefinement(0.01, 0, {}); // no outputs }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_rleja); grid.setSurplusRefinement(0.01, 0, {}); // no loaded values }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_chebyshev); gridLoadEN2(&grid); grid.setSurplusRefinement(0.01, 0, {}); // rule non-nested }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); gridLoadEN2(&grid); grid.setSurplusRefinement(0.01, 0, {}); // grid is localp }, [](void)->void{ TasmanianSparseGrid grid; grid.setSurplusRefinement(0.01, refine_classic, 0, 0); // grid not init }, [](void)->void{ TasmanianSparseGrid grid; grid.setSurplusRefinement(0.01, refine_classic, 0, {}); // grid not init }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 0, 3); grid.setSurplusRefinement(0.01, refine_classic, 0); // no outputs }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 3); grid.setSurplusRefinement(0.01, refine_classic, 0); // no loaded values }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_chebyshev); gridLoadEN2(&grid); grid.setSurplusRefinement(0.01, refine_classic, 0, std::vector()); // rule non-local }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_chebyshev); gridLoadEN2(&grid); grid.setSurplusRefinement(0.01, refine_classic, 0, 0); // rule non-local }, [](void)->void{ auto grid = makeEmpty(); grid.beginConstruction(); // cannot init construct on empty }, [](void)->void{ TasmanianSparseGrid grid; grid.setDomainTransform({}, {}); // grid is not initialized }, [](void)->void{ TasmanianSparseGrid grid; grid.setDomainTransform(nullptr, nullptr); // grid is not initialized }, [](void)->void{ TasmanianSparseGrid grid; grid.setConformalTransformASIN({4, 4}); // grid is not initialized }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_chebyshev); auto transform = grid.getConformalTransformASIN(); // transform not initialized }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 3, type_level, rule_chebyshev); std::vector pntr, indx; std::vector vals; std::vector x = {-0.33, 0.33}; grid.evaluateSparseHierarchicalFunctions(x, pntr, indx, vals); }, [](void)->void{ TasmanianSparseGrid grid; grid.makeGlobalGrid(1, 1, 10, type_level, rule_gausspatterson); // gauss-patterson rule with very large level }, [](void)->void{ const char *custom_filename = ExternalTester::findGaussPattersonTable(); auto grid = makeGlobalGrid(1, 1, 10, type_level, rule_customtabulated, {}, 0.0, 0.0, custom_filename); // custom-tabulated rule with very large level }, [](void)->void{ CustomTabulated custom; custom.read(ExternalTester::findGaussPattersonTable()); custom.getNumPoints(11); // level too high }, [](void)->void{ CustomTabulated custom; custom.read(ExternalTester::findGaussPattersonTable()); custom.getIExact(11); // level too high }, [](void)->void{ CustomTabulated custom; custom.read(ExternalTester::findGaussPattersonTable()); custom.getQExact(11); // level too high }, [](void)->void{ auto grid = makeSequenceGrid(2, 1, 1, type_level, rule_leja); gridLoadEN2(&grid); grid.removePointsByHierarchicalCoefficient(0.1, -1, nullptr); // grid is not localp or wavelet }, [](void)->void{ auto grid = makeEmpty(); auto integ = grid.integrateHierarchicalFunctions(); }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 0, type_level, rule_clenshawcurtis); std::vector x = {0.33, 0.33}; grid.evaluateSparseHierarchicalFunctionsGetNZ(x.data(), 1); // cannot call for Global grid }, [](void)->void{ auto grid = makeGlobalGrid(2, 1, 0, type_level, rule_clenshawcurtis); std::vector vals(5), x = {0.33, 0.33}; std::vector pntr(5), indx(5); grid.evaluateSparseHierarchicalFunctionsStatic(x.data(), 1, pntr.data(), indx.data(), vals.data()); // cannot call for Global grid }, [](void)->void{ auto grid = makeSequenceGrid(2, 1, 1, type_level, rule_leja); grid.setHierarchicalCoefficients({1.0, 2.0}); // not enough coefficients }, [](void)->void{ auto grid = makeLocalPolynomialGrid(2, 1, 1, rule_localp); std::vector s = grid.getGlobalPolynomialSpace(true); // only available for global, sequence and Fourier }, [](void)->void{ auto grid = makeEmpty(); grid.getPointsIndexes(); // cannot call on empty }, }; } bool GridUnitTester::testLAPACKInterface() { bool all_matched = true; #ifdef Tasmanian_ENABLE_BLAS // Initialize. const int N = 100; const double a = TasGrid::Maths::pi / 2; const double b = TasGrid::Maths::pi / 4; int M = N; int nsplit = 1; std::vector exact_eigs(N); for (int i=0; i D(N, a), E(N-1, b); std::vector W(N), Z(N*N), WORK1(2*N-2), WORK2(4*N); std::vector IBLOCK1(N), ISPLIT1(N), IWORK1(3*N); ISPLIT1[0] = N; IBLOCK1[0] = N; // Test LAPACK's dsterf function. TasBLAS::sterf(N, D.data(), E.data()); std::sort(D.begin(), D.end()); if (not doesMatch(D, exact_eigs)) { std::cout << "ERROR: failed LAPACK test at sterf()\n"; all_matched = false; } // Test LAPACK's dsteqr function. std::fill(D.begin(), D.end(), a); std::fill(E.begin(), E.end(), b); TasBLAS::steqr('N', N, D.data(), E.data(), Z.data(), 1, WORK1.data()); std::sort(D.begin(), D.end()); if (not doesMatch(D, exact_eigs)) { std::cout << "ERROR: failed LAPACK test at steqr()\n"; all_matched = false; } // Test LAPACK's dstebz function. std::fill(D.begin(), D.end(), a); std::fill(E.begin(), E.end(), b); TasBLAS::stebz('A', 'E', N, 0.0, 0.0, 1, N, 1e-13, D.data(), E.data(), M, nsplit, W.data(), IBLOCK1.data(), ISPLIT1.data(), WORK2.data(), IWORK1.data()); if (not doesMatch(W, exact_eigs)) { std::cout << "ERROR: failed LAPACK test at stebz()\n"; all_matched = false; } #endif return all_matched; } #endif TASMANIAN-8.1/SparseGrids/gridtestUnitTests.hpp000066400000000000000000000066711470551176200213660ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASGRID_UNIT_TESTS_HPP #define __TASGRID_UNIT_TESTS_HPP #include "gridtestCLICommon.hpp" enum UnitTests{ unit_none, unit_all, unit_cover, unit_except, unit_api, unit_c, unit_lapack }; class GridUnitTester{ public: GridUnitTester(); ~GridUnitTester(); static UnitTests hasTest(std::string const &s); void setVerbose(bool new_verbose); bool Test(UnitTests test); bool testAllException(); bool testAPIconsistency(); bool testCInterface(); bool testCoverUnimportant(); bool testLAPACKInterface(); protected: std::vector> getInvalidArgumentCalls() const; std::vector> getRuntimeErrorCalls() const; bool doesMatch(const std::vector &a, const std::vector &b, double prec = 1.E-12) const; bool doesMatch(const std::vector &a, const double b[], double prec = 1.E-12) const; bool doesMatch(const std::vector &a, const int b[]) const; bool doesMatch(size_t n, double a[], const double b[], double prec = 1.E-12) const; private: bool verbose; }; extern "C" int testInterfaceC(); #endif TASMANIAN-8.1/SparseGrids/gridtest_main.cpp000066400000000000000000000077701470551176200205030ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "gridtestExternalTests.hpp" #include "gridtestUnitTests.hpp" int main(int argc, const char ** argv){ //cout << " Phruuuuphrrr " << endl; // this is the sound that the Tasmanian devil makes std::deque args = stringArgs(argc, argv); // testing bool debug = false; bool debugII = false; bool verbose = false; bool seed_reset = false; TestList test = test_all; UnitTests utest = unit_none; int gpuid = -1; while (!args.empty()){ if (args.front() == "debug") debug = true; if (args.front() == "db") debugII = true; if (hasInfo(args.front())) verbose = true; if (hasRandom(args.front())) seed_reset = true; TestList test_maybe = ExternalTester::hasTest(args.front()); if (test_maybe != test_none) test = test_maybe; UnitTests utest_maybe = GridUnitTester::hasTest(args.front()); if (utest_maybe != unit_none) utest = utest_maybe; if (hasGpuID(args.front())){ args.pop_front(); gpuid = getGpuID(args); } args.pop_front(); } ExternalTester tester(1000); GridUnitTester utester; tester.setGPUID(gpuid); if (verbose) tester.setVerbose(true); if (verbose) utester.setVerbose(true); bool pass = true; if (debug){ tester.debugTest(); }else if (debugII){ tester.debugTestII(); }else{ if (seed_reset) tester.resetRandomSeed(); if (utest == unit_none){ if (test == test_all) pass = pass && utester.Test(unit_all); pass = pass && tester.Test(test); }else{ pass = pass && utester.Test(utest); } } return (pass) ? 0 : 1; } TASMANIAN-8.1/SparseGrids/tsgAcceleratedDataStructures.cpp000066400000000000000000000216651470551176200234610ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_ACCELERATED_DATA_STRUCTURES_CPP #define __TASMANIAN_SPARSE_GRID_ACCELERATED_DATA_STRUCTURES_CPP #include "tsgAcceleratedDataStructures.hpp" namespace TasGrid{ std::map AccelerationMeta::getStringToAccelerationMap(){ return { {"none", accel_none}, {"cpu-blas", accel_cpu_blas}, {"gpu-default", accel_gpu_default}, {"gpu-cublas", accel_gpu_cublas}, {"gpu-cuda", accel_gpu_cuda}, {"gpu-rocblas", accel_gpu_rocblas}, {"gpu-hip", accel_gpu_hip}, {"gpu-magma", accel_gpu_magma}}; } TypeAcceleration AccelerationMeta::getIOAccelerationString(const char * name){ try{ return getStringToAccelerationMap().at(name); }catch(std::out_of_range &){ return accel_none; } } const char* AccelerationMeta::getIOAccelerationString(TypeAcceleration accel){ switch (accel){ case accel_cpu_blas: return "cpu-blas"; case accel_gpu_default: return "gpu-default"; case accel_gpu_cublas: return "gpu-cublas"; case accel_gpu_cuda: return "gpu-cuda"; case accel_gpu_magma: return "gpu-magma"; default: return "none"; } } int AccelerationMeta::getIOAccelerationInt(TypeAcceleration accel){ switch (accel){ case accel_cpu_blas: return 1; case accel_gpu_default: return 3; case accel_gpu_cublas: return 4; case accel_gpu_cuda: return 5; case accel_gpu_magma: return 6; default: return 0; } } TypeAcceleration AccelerationMeta::getIOIntAcceleration(int accel){ switch (accel){ case 1: return accel_cpu_blas; case 3: return accel_gpu_default; case 4: return accel_gpu_cublas; case 5: return accel_gpu_cuda; case 6: return accel_gpu_magma; default: return accel_none; } } bool AccelerationMeta::isAccTypeGPU(TypeAcceleration accel){ switch (accel){ case accel_gpu_default: case accel_gpu_cublas: case accel_gpu_cuda: case accel_gpu_magma: return true; default: return false; } } TypeAcceleration AccelerationMeta::getAvailableFallback(TypeAcceleration accel){ // sparse grids are evaluated in 2 stages: // - s1: convert multi-index to matrix B // - s2: multiply matrix B by stored matrix A // Mode | Stage 1 device | Stage 2 device | Library for stage 2 // CUBLAS | CPU | GPU | Nvidia cuBlas (or cuSparse) // CUDA | GPU | GPU | Nvidia cuBlas (or cuSparse) // MAGMA | GPU* | GPU | UTK magma and magma_sparse // BLAS | CPU | CPU | BLAS // none | all done on CPU, still using OpenMP (if available) // note that CUDA, HIP and DPCPP are interchangeable based on the selected backend at compiler time #ifdef Tasmanian_ENABLE_DPCPP // temporary workaround // if (accel == accel_gpu_magma or accel == accel_gpu_cuda) // return accel_gpu_cublas; // return accel; #endif // accel_gpu_default should always point to the potentially "best" option (currently MAGMA) if (accel == accel_gpu_default) accel = accel_gpu_magma; #if !defined(Tasmanian_ENABLE_GPU) || !defined(Tasmanian_ENABLE_MAGMA) || !defined(Tasmanian_ENABLE_BLAS) // if any of the 3 acceleration modes is missing, then add a switch statement to guard against setting that mode switch(accel){ #ifndef Tasmanian_ENABLE_GPU // if CUDA is missing: just use the CPU case accel_gpu_cublas: case accel_gpu_cuda: #ifdef Tasmanian_ENABLE_BLAS accel = accel_cpu_blas; #else accel = accel_none; #endif break; #endif // Tasmanian_ENABLE_GPU #ifndef Tasmanian_ENABLE_MAGMA // MAGMA tries to use CUDA kernels with magma linear algebra, this CUDA is the next best thing case accel_gpu_magma: #ifdef Tasmanian_ENABLE_GPU accel = accel_gpu_cuda; #elif defined(Tasmanian_ENABLE_BLAS) accel = accel_cpu_blas; #else accel = accel_none; #endif break; #endif // Tasmanian_ENABLE_MAGMA #ifndef Tasmanian_ENABLE_BLAS // if BLAS is missing, do not attempt to use the GPU but go directly to "none" mode case accel_cpu_blas: accel = accel_none; break; #endif // Tasmanian_ENABLE_BLAS default: // compiler complains if there is no explicit "default", even if empty break; } #endif return accel; } AccelerationDomainTransform::AccelerationDomainTransform(AccelerationContext const *acc, std::vector const &transform_a, std::vector const &transform_b) : acceleration(acc){ // The points are stored contiguously in a vector with stride equal to num_dimensions // Using the contiguous memory in a contiguous fashion on the GPU implies that thread 0 works on dimension 0, thread 1 on dim 1 ... // But the number of dimensions is often way less than the number of threads // Therefore, we lump vectors together into large vectors of sufficient dimension // The dimension is least 512, but less than max CUDA threads 1024 // The domain transforms are padded accordingly num_dimensions = (int) transform_a.size(); padded_size = num_dimensions; while(padded_size < 512) padded_size += num_dimensions; std::vector rate(padded_size); std::vector shift(padded_size); int c = 0; for(int i=0; i void AccelerationDomainTransform::getCanonicalPoints(bool use01, const T *gpu_transformed_x, int num_x, GpuVector &gpu_canonical_x){ gpu_canonical_x.resize(acceleration, ((size_t) num_dimensions) * ((size_t) num_x)); TasGpu::dtrans2can(acceleration, use01, num_dimensions, num_x, padded_size, gpu_trans_a.data(), gpu_trans_b.data(), gpu_transformed_x, gpu_canonical_x.data()); } template void AccelerationDomainTransform::getCanonicalPoints(bool, float const[], int, GpuVector&); template void AccelerationDomainTransform::getCanonicalPoints(bool, double const[], int, GpuVector&); } #endif TASMANIAN-8.1/SparseGrids/tsgAcceleratedDataStructures.hpp000066400000000000000000001166421470551176200234660ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_ACCELERATED_DATA_STRUCTURES_HPP #define __TASMANIAN_SPARSE_GRID_ACCELERATED_DATA_STRUCTURES_HPP #include "tsgAcceleratedHandles.hpp" //! \internal //! \file tsgAcceleratedDataStructures.hpp //! \brief Data structures for interacting with CUDA and MAGMA environments. //! \author Miroslav Stoyanov //! \ingroup TasmanianAcceleration //! //! Classes and namespaces that wrap around basic CUDA and MAGMA functionality, //! the classes allow RAII style of memory management for CUDA GPU arrays, //! as well as handy encapsulation of the cuBlas/cuSparse/MAGMA handles and streams. /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianAcceleration Classes and functions used for acceleration methods * * \par RAII Memory Management * CUDA uses C-style of memory management with cudaMalloc(), cudaMemcopy(), cudaFree(), * but templated C++ std::vector-style class is far more handy and more fail-safe. * The \b GpuVector template class guards against memory leaks and offers more seamless * integration between CPU and GPU data structures. * See the \b GpuVector documentation for details. * * \par Streams and Handles Encapsulation * CUDA linear algebra libraries (as well as MAGAM), use streams and handles for all their calls. * The handles have to be allocated, deleted, and passed around which causes unnecessary code clutter. * Encapsulating the handles in a single \b GpuEngine class greatly simplifies the work-flow. * Furthermore, some (sparse) linear operations require multiple calls to CUDA/MAGMA libraries, * and it is easier to combine those into a single call to a \b GpuEngine method. * * \par Acceleration Metadata * The \b AccelerationMeta namespace offers several methods used throughout the library and in the testing: * - Tasmanian specific acceleration fallback logic * - Reading CUDA device properties, e.g., number of devices or total memory * - Error handling for common CUDA/cuBlas/cuSparse calls * * \par C++ Wrappers to Fortran BLAS API * The standard BLAS API follows Fortran calling conventions, * e.g., call by value and underscore at the end of function names. * A C++ wrapper is provided that handles Tasmanian specific cases of * dense matrix-matrix and matrix-vector multiplication using C++ compatible API. * \endinternal */ namespace TasGrid{ struct AccelerationContext; // forward declaration, CUDA and HIP GpuVector do not use the context, but DPC++ needs it /*! * \ingroup TasmanianAcceleration * \brief Template class that wraps around a single GPU array, providing functionality that mimics std::vector. * * \par Wraps Around a GPU Array * The class can be instantiated with either \b int, \b float or \b double (other types are not currently available). * The class can either allocate (and deallocate with the descructor) an array of desired size that resided in the GPU device memory, * and load/unload data to a CPU std::vector or array with the same type. * * Note that the class does not provide a single entry access and it is not copyable, only movable in assignment and constructor. */ template class GpuVector{ public: //! \brief Delete the copy-constructor. GpuVector(GpuVector const &) = delete; //! \brief Delete the copy-assignment. GpuVector& operator =(GpuVector const &) = delete; //! \brief Allow for move-construction. GpuVector(GpuVector &&other) : num_entries(Utils::exchange(other.num_entries, 0)), gpu_data(Utils::exchange(other.gpu_data, nullptr)) #ifdef Tasmanian_ENABLE_DPCPP , sycl_queue(other.sycl_queue) #endif {} //! \brief Allow for move-assignment. GpuVector& operator =(GpuVector &&other){ GpuVector temp(std::move(other)); std::swap(num_entries, temp.num_entries); std::swap(gpu_data, temp.gpu_data); #ifdef Tasmanian_ENABLE_DPCPP std::swap(sycl_queue, temp.sycl_queue); #endif return *this; } //! \brief Default constructor, creates an empty (null) array. GpuVector() : num_entries(0), gpu_data(nullptr){} //! \brief Construct a vector with \b count number of entries. GpuVector(AccelerationContext const *acc, size_t count) : num_entries(0), gpu_data(nullptr){ resize(acc, count); } /*! * \brief Same as \b GpuVector(dim1 * dim2), but guards against overflow. * * Many of the Tasmanian data-structures are inherently two-dimensional, * for example, passing number of points and number of dimensions separately makes the code more readable, * and both integers are converted to size_t before multiplication which prevents overflow. * Note: the dimensions \b will \b not be stored, the underlying data is still one dimensional. */ GpuVector(AccelerationContext const *acc, int dim1, int dim2) : num_entries(0), gpu_data(nullptr){ resize(acc, Utils::size_mult(dim1, dim2)); } //! \brief Create a vector with size that matches \b cpu_data and copy the data to the GPU device. GpuVector(AccelerationContext const *acc, const std::vector &cpu_data) : num_entries(0), gpu_data(nullptr){ load(acc, cpu_data); } //! \brief Construct a vector and load with date provided on to the cpu. GpuVector(AccelerationContext const *acc, int dim1, int dim2, T const *cpu_data) : num_entries(0), gpu_data(nullptr){ load(acc, Utils::size_mult(dim1, dim2), cpu_data); } //! \brief Construct a vector by loading from a given range. template GpuVector(AccelerationContext const *acc, IteratorLike ibegin, IteratorLike iend) : GpuVector(){ load(acc, ibegin, iend); } //! \brief Destructor, release all allocated memory. ~GpuVector(){ clear(); } //! \brief Return the current size of the GPU array. size_t size() const{ return num_entries; } //! \brief Get a reference to the GPU array, which an be used as input to GPU libraries and kernels. T* data(){ return gpu_data; } //! \brief Get a const-reference to the GPU array, which an be used as input to GPU libraries and kernels. const T* data() const{ return gpu_data; } //! \brief Clear all data currently stored in the vector and allocate a new array (unlike std::vector this does not relocate the old data). void resize(AccelerationContext const *acc, size_t count); //! \brief Delete all allocated memory and reset the array to empty. void clear(); //! \brief Return \b true if the \b size() is zero. bool empty() const{ return (num_entries == 0); } //! \brief Copy the content of \b cpu_data to the GPU device, all pre-existing data is deleted and the vector is resized to match \b cpu_data. void load(AccelerationContext const *acc, const std::vector &cpu_data){ load(acc, cpu_data.size(), cpu_data.data()); } //! \brief Load from a range defined by the begin and end, converts if necessary. template void load(AccelerationContext const *acc, IteratorLike ibegin, IteratorLike iend){ load(acc, std::distance(ibegin, iend), &*ibegin); } /*! * \brief Takes a vector with entries of different precision, converts and loads. * * Used when the CPU vectors are stored in double-precision format while the GPU entries are prepared to work with single-precision. */ template Utils::use_if::value> load(AccelerationContext const *acc, const std::vector &cpu_data){ load(acc, cpu_data.size(), cpu_data.data()); } /*! * \brief Copy the first \b count entries of \b cpu_data to the GPU device. * * If \b count does not match the current size, the current array will be deleted and new array will be allocated * (even if \b size() exceeds \b count). * The final vector size will match \b count. * However, if \b count matches \b size(), the data is overwritten but no arrays will be allocated, deleted, or de-aliased. */ void load(AccelerationContext const *acc, size_t count, const T* cpu_data); /*! * \brief Takes a vector with entries of different precision, converts and loads. * * Used when the CPU data is stored in double-precision format while the GPU entries are prepared to work with single-precision. */ template Utils::use_if::value> load(AccelerationContext const *acc, size_t count, const U* cpu_data){ std::vector converted(count); std::transform(cpu_data, cpu_data + count, converted.begin(), [](U const &x)->T{ return static_cast(x); }); load(acc, converted); } //! \brief Copy the data from the GPU array to \b cpu_data, the \b cpu_data will be resized and overwritten. void unload(AccelerationContext const *acc, std::vector &cpu_data) const{ cpu_data.resize(num_entries); unload(acc, cpu_data.data()); } //! \brief Return a CPU vector holding the data of the GPU. std::vector unload(AccelerationContext const *acc) const{ std::vector y; unload(acc, y); return y; } //! \brief Copy the first \b num entries to the \b cpu_data buffer, assumes that the buffer is sufficiently large. void unload(AccelerationContext const *acc, size_t num, T* cpu_data) const; //! \brief Copy the data from the GPU array to the \b cpu_data buffer, assumes that the buffer is sufficiently large. void unload(AccelerationContext const *acc, T* cpu_data) const{ unload(acc, num_entries, cpu_data); } //! \brief Move the data to the \b external array, the vector is set to empty (unlike move command on std::vector). T* eject(){ T* external = gpu_data; gpu_data = nullptr; num_entries = 0; return external; } //! \brief The data-type of the vector entries. using value_type = T; private: size_t num_entries; // keep track of the size, update on every call that changes the gpu_data T *gpu_data; // the GPU array #ifdef Tasmanian_ENABLE_DPCPP void* sycl_queue; #endif }; /*! * \ingroup TasmanianAcceleration * \brief Wrapper class around calls GPU accelerated linear algebra libraries. * * The class also manages the required handles and queues and holds the context of the active GPU device. */ struct GpuEngine{ #ifdef Tasmanian_ENABLE_CUDA //! \brief Manually sets the cuBlas handle, handle must be a valid cublasHandle_t associated with this CUDA device. void setCuBlasHandle(void *handle); //! \brief Manually sets the cuSparse handle, handle must be a valid cusparseHandle_t associated with this CUDA device. void setCuSparseHandle(void *handle); //! \brief Manually sets the cuSparse handle, handle must be a valid cusolverDnHandle_t associated with this CUDA device. void setCuSolverDnHandle(void *handle); //! \brief Holds the cuBlas handle. std::unique_ptr> cublas_handle; //! \brief Holds the cuSparse handle. std::unique_ptr> cusparse_handle; //! \brief Holds the cuSolver handle. std::unique_ptr> cusolver_handle; #endif #ifdef Tasmanian_ENABLE_HIP //! \brief Set the rocBlas handle, handle must be a valid rocblas_handle associated with this ROCm device. void setRocBlasHandle(void *handle); //! \brief Set the rocSparse handle, handle must be a valid rocsparse_handle associated with this ROCm device. void setRocSparseHandle(void *handle); //! \brief Holds the rocBlas handle. std::unique_ptr> rblas_handle; //! \brief Holds the rocSparse handle. std::unique_ptr> rsparse_handle; #endif #ifdef Tasmanian_ENABLE_DPCPP //! \brief Set a user provided sycl::queue. void setSyclQueue(void *queue); //! \brief Holds the actual queue. std::unique_ptr> internal_queue; #endif //! \brief Avoids an empty engine when no acceleration is enabled, allows for default constructor/move/copy, skips extraneous calls to MAGMA init. std::unique_ptr called_magma_init; }; //! \internal //! \brief Implements the domain transform algorithms in case the user data is provided on the GPU. //! \ingroup TasmanianAcceleration //! Takes the upper and lower bounds of a hypercube and transforms the user provided points to the canonical domain (-1, 1) or (0, 1). //! The transformation is done on the GPU to avoid extraneous data movement. //! //! \b Note: Conformal mapping and the non-linear Gauss-Hermite and Gauss-Laguerre transforms are not supported. class AccelerationDomainTransform{ public: //! \brief Constructor, load the transform data to the GPU, the vectors are the same as used in the \b TasmanianSparseGrid class. AccelerationDomainTransform(AccelerationContext const *, std::vector const &transform_a, std::vector const &transform_b); /*! * \brief Transform a set of points, used in the calls to \b evaluateHierarchicalFunctionsGPU() * Takes the user provided \b gpu_transformed_x points of dimension matching the grid num_dimensions * and total number \b num_x. * The \b gpu_canonical_x is resized to match \b gpu_transformed_x and it loaded with the corresponding canonical points. * The \b use01 flag indicates whether to use canonical domain (0, 1) (Fourier grids), or (-1, 1) (almost everything else). */ template void getCanonicalPoints(bool use01, T const gpu_transformed_x[], int num_x, GpuVector &gpu_canonical_x); private: // these actually store the rate and shift and not the hard upper/lower limits GpuVector gpu_trans_a, gpu_trans_b; int num_dimensions, padded_size; AccelerationContext const *acceleration; }; //! \internal //! \brief Wrappers around custom CUDA kernels to handle domain transforms and basis evaluations, the kernels are instantiated in tsgCudaKernels.cu //! \ingroup TasmanianAcceleration namespace TasGpu{ //! \internal //! \brief Uses custom kernel to convert \b transformed points to \b canonical points, all arrays live on the CUDA device. //! \ingroup TasmanianAcceleration //! The array \b gpu_x_transformed is provided by the user and must be of size \b num_x times \b dims. //! The points are stored contiguously in strides of \b dim (identical to all other calls). //! In order to facilitate contiguous memory access, it is most efficient to assign each thread to different dimension, //! but the dimensions are much less than the threads. //! Thus, we pad the transforms \b gpu_trans_a and \b gpu_trans_b as if they are applied to much larger vectors (of dimension \b pad_size). //! The \b pad_size must be a multiple of \b dims, but \b num_x doesn't have to divide into \b pad_size. //! The \b gpu_trans_a and \b gpu_trans_b must have length \b pad_size and must contain the rate and shift of the transform (\b not the upper/lower limits). //! //! The \b use01 indicates whether to use canonical interval (0, 1) or (-1, 1). //! This is called from \b AccelerationDomainTransform::getCanonicalPoints(). //! //! See the implementation of \b AccelerationDomainTransform::load() for more details. template void dtrans2can(AccelerationContext const *acc, bool use01, int dims, int num_x, int pad_size, const double *gpu_trans_a, const double *gpu_trans_b, const T *gpu_x_transformed, T *gpu_x_canonical); //! \internal //! \brief Evaluate the basis functions for a local polynomial grid using the \b DENSE algorithm. //! \ingroup TasmanianAcceleration //! Used for basis evaluations in \b GridLocalPolynomial with \b order (0, 1, and 2) and \b rule. //! The grid has \b num_dimensions and \b num_basis functions (equal to the number of points in the grid). //! The number of locations to evaluate is \b num_x, and \b gpu_x must have size \b num_x times \b num_dimensions, and \b gpu_x must be on a canonical interval. //! The output matrix \b gpu_y has dimension \b num_basis (contiguous dimension) times \b num_x. //! //! The grid nodes and the associated support are "encoded" in \b gpu_nodes and \b gpu_support, //! where negative support is used to handle special cases such as global support on level 1 (rule semi-localp). //! The interpretation of the negative support must be synchronized between the kernel \b tasgpu_devalpwpoly_feval() and \b GridLocalPolynomial::encodeSupportForGPU(). template void devalpwpoly(AccelerationContext const *acc, int order, TypeOneDRule rule, int num_dimensions, int num_x, int num_basis, const T *gpu_x, const T *gpu_nodes, const T *gpu_support, T *gpu_y); //! \internal //! \brief Evaluate the basis functions for a local polynomial grid using the \b SPARSE algorithm. //! \ingroup TasmanianAcceleration //! The inputs are identical to \b devalpwpoly() with the addition of hierarchy vectors \b gpu_hpntr, \b gpu_hindx, and \b gpu_roots. //! The hierarchy vectors define a series of trees, one for each entry in \b gpu_roots, and all three nodes combined are indexed from 0 to gpu_spntr.size(). //! The \b gpu_hpntr holds the offsets of the children of each node and the indexes of the children are stored in \b gpu_sindx. //! The format is identical to row compressed sparse matrix. //! //! The output vectors \b gpu_spntr, \b gpu_sindx and \b gpu_svals form a row compressed matrix, //! e.g., in format that can directly interface with Nvidia cusparseDcsrmm2(). template void devalpwpoly_sparse(AccelerationContext const *acc, int order, TypeOneDRule rule, int dims, int num_x, const T *gpu_x, const GpuVector &gpu_nodes, const GpuVector &gpu_support, const GpuVector &gpu_hpntr, const GpuVector &gpu_hindx, const GpuVector &gpu_hroots, GpuVector &gpu_spntr, GpuVector &gpu_sindx, GpuVector &gpu_svals); //! \internal //! \brief Evaluate the basis for a Sequence grid. //! \ingroup TasmanianAcceleration //! The evaluation points are defined on a canonical interval and given in \b gpu_x with size \b dims times \b num_x. //! The \b max_levels indicates the maximum level in each direction (one more than the vector stored in the GridSequence data structure), //! the vector is required to compute the offsets of the intermediate cache for the Newton polynomials. //! The \b points holds the same information as the \b MultiIndexSet, but in transposed order, i.e., the dimensions of the multi-indexes are contiguous. //! The kernel handles one dimension at a time, hence the switched order compared to the CPU which handles one multi-index at a time. //! The \b ndoes vector has the cached 1D nodes and \b coeffs holds the cached coefficients of the Newton polynomials. //! //! The output is \b gpu_result which must have dimension \b num_x by \b num_nodes.size() / \b dims. template void devalseq(AccelerationContext const *acc, int dims, int num_x, const std::vector &max_levels, const T *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, T *gpu_result); //! \internal //! \brief Evaluate the basis for a Fourier grid. //! \ingroup TasmanianAcceleration //! The logic is identical to \b devalseq(), except the Fourier polynomials do not require nodes or coefficients. //! The output is two real arrays of size \b num_x by \b num_nodes.size() / \b dims corresponding to the real and complex parts of the basis. template void devalfor(AccelerationContext const *acc, int dims, int num_x, const std::vector &max_levels, const T *gpu_x, const GpuVector &num_nodes, const GpuVector &points, T *gpu_wreal, typename GpuVector::value_type *gpu_wimag); /*! * \internal * \ingroup TasmanianAcceleration * \brief Evaluate the basis for Global grid. * * The logic is more complicated due to the more general nature of the grid. * \endinternal */ template void devalglo(AccelerationContext const *acc, bool is_nested, bool is_clenshawcurtis0, int dims, int num_x, int num_p, int num_basis, T const *gpu_x, GpuVector const &nodes, GpuVector const &coeff, GpuVector const &tensor_weights, GpuVector const &nodes_per_level, GpuVector const &offset_per_level, GpuVector const &map_dimension, GpuVector const &map_level, GpuVector const &active_tensors, GpuVector const &active_num_points, GpuVector const &dim_offsets, GpuVector const &map_tensor, GpuVector const &map_index, GpuVector const &map_reference, T *gpu_result); /*! * \ingroup TasmanianAcceleration * \brief Fills the \b data with the provided real number at the given stride. */ void fillDataGPU(AccelerationContext const *acc, double value, long long N, long long stride, double data[]); /*! * \ingroup TasmanianAcceleration * \brief Similar to copy_n, copies the data from the CPU to the GPU. */ template void load_n(AccelerationContext const *acc, T const *cpu_data, size_t num_entries, T *gpu_data); /*! * \ingroup TasmanianAcceleration * \brief Similar to copy_n, copies the data from the CPU to the GPU. */ template Utils::use_if::value> load_n(AccelerationContext const *acc, U const *cpu_data, size_t num_entries, T *gpu_data){ std::vector converted(num_entries); std::transform(cpu_data, cpu_data + num_entries, converted.begin(), [](U const &x)->T{ return static_cast(x); }); load_n(acc, converted.data(), num_entries, gpu_data); } // #define __TASMANIAN_COMPILE_FALLBACK_CUDA_KERNELS__ // uncomment to compile a bunch of custom CUDA kernels that provide some functionality similar to cuBlas #ifdef __TASMANIAN_COMPILE_FALLBACK_CUDA_KERNELS__ // CUDA kernels that provide essentially the same functionality as cuBlas and MAGMA, but nowhere near as optimal // those functions should not be used in a Release or production builds // the kernels are useful because they are simple and do not depend on potentially poorly documented 3d party library // since the kernels are useful for testing and some debugging, the code should not be deleted (for now), but also don't waste time compiling in most cases void cudaDgemm(int M, int N, int K, const double *gpu_a, const double *gpu_b, double *gpu_c); // lazy cuda dgemm, nowhere near as powerful as cuBlas, but does not depend on cuBlas // gpu_a is M by K, gpu_b is K by N, gpu_c is M by N, all in column-major format // on exit gpu_c = gpu_a * gpu_b void cudaSparseMatmul(int M, int N, int num_nz, const int* gpu_spntr, const int* gpu_sindx, const double* gpu_svals, const double *gpu_B, double *gpu_C); // lazy cuda sparse dgemm, less efficient (especially for large N), but more memory conservative then cusparse as there is no need for a transpose // C is M x N, B is K x N (K is max(gpu_sindx)), both are given in row-major format, num_nz/spntr/sindx/svals describe row compressed A which is M by K // on exit C = A * B void cudaSparseVecDenseMat(int M, int N, int num_nz, const double *A, const int *indx, const double *vals, double *C); // dense matrix A (column major) times a sparse vector defiend by num_nz, indx, and vals // A is M by N, C is M by 1, // on exit C = A * (indx, vals) void convert_sparse_to_dense(int num_rows, int num_columns, const int *gpu_pntr, const int *gpu_indx, const double *gpu_vals, double *gpu_destination); // converts a sparse matrix to a dense representation (all data sits on the gpu and is pre-allocated) #endif } //! \internal //! \brief Common methods for manipulating acceleration options and reading CUDA environment properties. //! \ingroup TasmanianAcceleration namespace AccelerationMeta{ //! \internal //! \brief Convert the string (coming from C or Python) into an enumerated type. //! \ingroup TasmanianAcceleration TypeAcceleration getIOAccelerationString(const char * name); //! \brief Creates a map with \b std::string rule names (used by C/Python/CLI) mapped to \b TypeAcceleration enums. std::map getStringToAccelerationMap(); //! \internal //! \brief Convert the enumerated type to a string, the inverse of \b getIOAccelerationString() //! \ingroup TasmanianAcceleration const char* getIOAccelerationString(TypeAcceleration accel); //! \internal //! \brief Convert the integer (coming from Fortran) into an enumerated type. //! \ingroup TasmanianAcceleration int getIOAccelerationInt(TypeAcceleration accel); //! \internal //! \brief Convert the enumerated type to an integer, the inverse of \b getIOAccelerationInt() //! \ingroup TasmanianAcceleration TypeAcceleration getIOIntAcceleration(int accel); //! \internal //! \brief Returns \b true if \b accele is cuda, cublas or magma. //! \ingroup TasmanianAcceleration bool isAccTypeGPU(TypeAcceleration accel); //! \brief Identifies whether the acceleration mode is available. inline bool isAvailable(TypeAcceleration accel){ switch(accel){ #ifdef Tasmanian_ENABLE_MAGMA case accel_gpu_magma: return true; #endif #ifdef Tasmanian_ENABLE_CUDA case accel_gpu_cuda: return true; case accel_gpu_cublas: return true; #endif #ifdef Tasmanian_ENABLE_HIP case accel_gpu_hip: return true; case accel_gpu_rocblas: return true; #endif #ifdef Tasmanian_ENABLE_DPCPP case accel_gpu_cuda: return true; case accel_gpu_cublas: return true; #endif #ifdef Tasmanian_ENABLE_BLAS case accel_cpu_blas: return true; #endif case accel_none: return true; default: return false; } } //! \internal //! \brief Implements fallback logic, if \b accel has been enabled through CMake then this returns \b accel, otherwise it returns the "next-best-thing". //! \ingroup TasmanianAcceleration //! This function always returns a valid acceleration type. //! The fallback logic is documented with the enumerated type \b TasGrid::TypeAcceleration. TypeAcceleration getAvailableFallback(TypeAcceleration accel); //! \internal //! \brief Return the number of visible GPU devices. //! \ingroup TasmanianAcceleration int getNumGpuDevices(); //! \internal //! \brief Selects the active device for this CPU thread, not supported for DPC++. //! \ingroup TasmanianAcceleration //! The \b deviceID must be a valid ID (between 0 and getNumGpuDevices() -1). void setDefaultGpuDevice(int deviceID); //! \internal //! \brief Return the memory available in the device (in units of bytes). //! \ingroup TasmanianAcceleration //! The \b deviceID must be a valid ID (between 0 and getNumGpuDevices() -1). unsigned long long getTotalGPUMemory(int deviceID); //! \internal //! \brief Returns the name of the selected GPU device, empty string if no device is available or the index is out of bounds. //! \ingroup TasmanianAcceleration //! The \b deviceID must be a valid ID (between 0 and getNumGpuDevices() -1). std::string getGpuDeviceName(int deviceID); //! \internal //! \brief Copy a device array to the main memory, used for testing only, always favor using \b GpuVector (if possible). //! \ingroup TasmanianAcceleration template void recvGpuArray(AccelerationContext const*, size_t num_entries, const T *gpu_data, std::vector &cpu_data); //! \internal //! \brief Deallocate device array, used primarily for testing, always favor using \b GpuVector (if possible). //! \ingroup TasmanianAcceleration template void delGpuArray(AccelerationContext const*, T *x); /*! * \ingroup TasmanianAcceleration * \brief Creates a new cuBlas handle, used in unit-testing only. */ void *createCublasHandle(); /*! * \ingroup TasmanianAcceleration * \brief Destroys the cuBlas handle, used in unit-testing only. */ void deleteCublasHandle(void *); } /*! * \internal * \ingroup TasmanianAcceleration * \brief Wrapper class around GPU device ID, acceleration type and GpuEngine. * * Single acceleration context held by the TasmanianSparseGrid class and aliased into each of the sub-classes. * The context is modified through the main class and is persistent on move, copy and read. * The sub-classes hold only a const pointer and can read and use the associated variables and the engine. * \endinternal */ struct AccelerationContext{ //! \brief Defines the sparse-dense algorithm flavors, whenever applicable. enum AlgorithmPreference{ //! \brief Use dense algorithm. algorithm_dense, //! \brief Use sparse algorithm. algorithm_sparse, //! \brief Use automatically select based on heuristics. algorithm_autoselect }; /*! * \brief Defines the types of acceleration context updates so they can be linked to acceleration cache updates. * * The update methods will generate a change event that may require an update of the acceleration cache. * For example, switching to a different GPU device means that the cache from the old device must be cleared. */ enum ChangeType{ //! \brief No change, do nothing. change_none, //! \brief Change the associated GPU device. change_gpu_device, //! \brief Change from BLAS or none to a GPU acceleration mode. change_gpu_enabled, //! \brief Change BLAS to none or none to BLAS. change_cpu_blas, //! \brief Change the sparse-dense AlgorithmPreference. change_sparse_dense }; //! \brief The current active acceleration mode. TypeAcceleration mode; //! \brief The preference to use dense or sparse algorithms. AlgorithmPreference algorithm_select; //! \brief If using a GPU acceleration mode, holds the active device. int device; //! \brief Holds the context to the GPU TPL handles, e.g., MAGMA queue. mutable std::unique_ptr engine; //! \brief Returns the default acceleration mode, cpu_blas if BLAS is enabled and none otherwise. inline static constexpr TypeAcceleration getDefaultAccMode() { #ifdef Tasmanian_ENABLE_BLAS return accel_cpu_blas; #else return accel_none; #endif } //! \brief Returns the default acceleration device, CUDA/HIP use GPU 0, SYCL uses -1 which uses sycl::default_selector_v inline static constexpr int getDefaultAccDevice() { #ifdef Tasmanian_ENABLE_DPCPP return -1; #else return 0; #endif } //! \brief Creates a default context, the device id is set to 0 and acceleration is BLAS (if available) or none. AccelerationContext() : mode(getDefaultAccMode()), algorithm_select(algorithm_autoselect), device(getDefaultAccDevice()){} //! \brief Sets algorithm affinity in the direction of sparse. ChangeType favorSparse(bool favor){ AlgorithmPreference new_preference = [=]()->AlgorithmPreference{ if (favor){ return (algorithm_select == algorithm_dense) ? algorithm_autoselect : algorithm_sparse; }else{ return (algorithm_select == algorithm_sparse) ? algorithm_autoselect : algorithm_dense; } }(); if (new_preference != algorithm_select){ algorithm_select = new_preference; return change_sparse_dense; }else{ return change_none; } } //! \brief Returns true if BLAS is enabled and the current mode is not none. bool blasCompatible() const{ #ifdef Tasmanian_ENABLE_BLAS return (mode != accel_none); #else return false; #endif } //! \brief Returns true if the current mode implies the use of custom GPU kernels. bool useKernels() const{ #if defined(Tasmanian_ENABLE_CUDA) || defined(Tasmanian_ENABLE_HIP) return ((mode == accel_gpu_cuda) or (mode == accel_gpu_magma)); #else return false; #endif } //! \brief Returns the ChangeType if enable() is called, but does not change the acceleration. ChangeType testEnable(TypeAcceleration acc, int new_gpu_id) const{ TypeAcceleration effective_acc = AccelerationMeta::getAvailableFallback(acc); #ifdef Tasmanian_ENABLE_DPCPP if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < -1 or new_gpu_id >= AccelerationMeta::getNumGpuDevices()))) throw std::runtime_error("Invalid GPU device ID, see ./tasgrid -v for list of detected devices."); #else if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < 0 or new_gpu_id >= AccelerationMeta::getNumGpuDevices()))) throw std::runtime_error("Invalid GPU device ID, see ./tasgrid -v for list of detected devices."); #endif ChangeType mode_change = (effective_acc == mode) ? change_none : change_cpu_blas; ChangeType device_change = (device == new_gpu_id) ? change_none : change_gpu_device; if (on_gpu()){ return (AccelerationMeta::isAccTypeGPU(effective_acc)) ? device_change : change_gpu_device; }else{ return (AccelerationMeta::isAccTypeGPU(effective_acc)) ? change_gpu_enabled : mode_change; } } //! \brief Accepts parameters directly from TasmanianSparseGrid::enableAcceleration() void enable(TypeAcceleration acc, int new_gpu_id){ // get the effective new acceleration mode (use the fallback if acc is not enabled) TypeAcceleration effective_acc = AccelerationMeta::getAvailableFallback(acc); // if switching to a GPU mode, check if the device id is valid #ifdef Tasmanian_ENABLE_DPCPP if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < -1 or new_gpu_id >= AccelerationMeta::getNumGpuDevices()))) throw std::runtime_error("Invalid GPU device ID, see ./tasgrid -v for list of detected devices."); #else if (AccelerationMeta::isAccTypeGPU(effective_acc) and ((new_gpu_id < 0 or new_gpu_id >= AccelerationMeta::getNumGpuDevices()))) throw std::runtime_error("Invalid GPU device ID, see ./tasgrid -v for list of detected devices."); #endif if (AccelerationMeta::isAccTypeGPU(effective_acc)){ // if the new mode is GPU-based, make an engine or reset the engine if the device has changed // if the engine exists and the device is not changed, then keep the existing engine if (!engine or new_gpu_id != device) engine = Utils::make_unique(); }else{ engine.reset(); } // assign the new values for the mode and device mode = effective_acc; device = new_gpu_id; } //! \brief Set default device. void setDevice() const{ AccelerationMeta::setDefaultGpuDevice(device); } //! \brief Custom convert to \b GpuEngine operator GpuEngine* () const{ return engine.get(); } //! \brief Returns true if any of the GPU-based acceleration modes have been enabled. bool on_gpu() const{ return !!engine; } }; #ifdef Tasmanian_ENABLE_DPCPP /*! * \internal * \ingroup TasmanianAcceleration * \brief Class holding the sycl queue used for internal testing. * * Testing uses multiple Tasmanian objects created and destroyed a lot of those. * Creating lots of sycl queues causes the jit system to keep recompiling the same kernels, * testing goes better when using a single queue. * The queue is created internally and reused for all tests, if InternalSyclQueue::init_testing() * has not been called, then regular internal queue would be used (separate for each object). * Note that in all cases, the user can provide their own sycl queue. * \endinternal */ struct InternalSyclQueue{ //! \brief Default constructor, assume we are not in a testing mode. InternalSyclQueue() : use_testing(false){} //! \brief Initialize the testing, in which case the internal queue would be used in place of a new queue. void init_testing(int gpuid); //! \brief Auto-converts to a non-owning std::unique_ptr. operator std::unique_ptr> (){ return std::unique_ptr>(test_queue.get(), HandleDeleter(false)); } //! \brief Indicates whether this is a testing run. bool use_testing; //! \brief Holds the internal sycl::queue for testing. std::unique_ptr> test_queue; }; /*! * \internal * \ingroup TasmanianAcceleration * \brief Holds an internal queue for testing purposes. * * \endinternal */ extern InternalSyclQueue test_queue; #endif } #endif // __TASMANIAN_SPARSE_GRID_ACCELERATED_DATA_STRUCTURES_HPP TASMANIAN-8.1/SparseGrids/tsgAcceleratedHandles.hpp000066400000000000000000000130751470551176200220630ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_ACCELERATED_HANDLES #define __TASMANIAN_SPARSE_GRID_ACCELERATED_HANDLES #include "tsgEnumerates.hpp" namespace TasGrid{ /*! * \internal * \ingroup TasmanianAcceleration * \brief Type tags for the different handle types. * * \endinternal */ namespace AccHandle{ //! \brief cuBlas handle. struct Cublas{}; //! \brief cuSparse handle. struct Cusparse{}; //! \brief cuSolver handle. struct Cusolver{}; //! \brief rocBlas handle. struct Rocblas{}; //! \brief rocSparse handle. struct Rocsparse{}; //! \brief SYCL queue handle. struct Syclqueue{}; } /*! * \internal * \ingroup TasmanianAcceleration * \brief Deletes the handle, specialized for each TPL backend and tag in TasGrid::AccHandle namepace. * * \endinternal */ template void deleteHandle(int*); /*! * \internal * \ingroup TasmanianAcceleration * \brief Deleter template for the GPU handles, e.g., cuBlas and rocBlas * * The deleter is used in conjunction with std::unique_ptr to provide both type-safety * and RAII resource management for the opaque pointer handles for TPL such as cuBlas and rocBlas. * The delete operation is defined in the corresponding TPL file. * The deleter is initialized with ownership flag which is indicated whether the associated * handle should or should not be deleted, e.g., whether the handle was created internally * or handed down by the user. * * Effectively, the deleter with init_own set to false will turn the associated std::unique_ptr * into a non-owning container. The positive side of this approach include: * - the rest of the code can refer to a single unique_ptr, e.g., this bundles the ownership flag * into the object * - the rest of the code can utilize all properties of std::unique_ptr, e.g., automatically * initializing and creating/deleting the proper copy and move constructor and assignment operators * - the C++ code outside of the TasGrid::deleteHandle() specializations looks like modern C++ * * The negative side of the above is that a non-owning std::unique_ptr is unexpected and violates * the spirit of the container, and possibly the whole point of the container. * However, this hack is necessitated by the mix of C-style of memory management for cuBlas/rocBlas * handles together with the C++ code. The alternative to this hack is to follow a C-style of code * throughout and keeping separate variables to indicate ownership, manually deleting constructors, * manually implementing move semantics, and losing C++ abstraction and automation. * The loss of abstraction would be obvious to a causal reader, but the code will be prone to all * problems that come without RAII regardless of how diligent or how familiar with Tasmanian * a contributor may be. * Therefore, this deleter is implemented to allow the use of std::unique_ptr in either owning or non-owning mode. * \endinternal */ template struct HandleDeleter{ //! \brief Constructor indicating the ownership of the handle. HandleDeleter(bool init_own = true) : own(init_own){} //! \brief Deletes the handle, if owned; nothing otherwise. void operator()(int *p) const { if (own) deleteHandle(p); } //! \brief Save the own/not own state. bool own; }; } #endif TASMANIAN-8.1/SparseGrids/tsgCacheLagrange.hpp000066400000000000000000000233261470551176200210340ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_CACHE_LAGRANGE_HPP #define __TSG_CACHE_LAGRANGE_HPP /*! * \internal * \file tsgCacheLagrange.hpp * \brief Cache data structure for evaluate with Global grids. * \author Miroslav Stoyanov * \ingroup TasmanianAcceleration * * \endinternal */ #include "tsgGridCore.hpp" namespace TasGrid{ /*! * \internal * \ingroup TasmanianAcceleration * \brief Cache that holds the values of 1D Lagrange polynomials. * * Global grids have the most complex evaluation procedure, * Lagrange polynomials have to be evaluated for each direction and \em each \em level, * before the weighted sum can be accumulated to compute the values of the basis functions. * The CacheLagrange class computes the values of the Lagrange polynomials * and caches them for easy access. * \endinternal */ template class CacheLagrange{ public: /*! * \brief Constructor that takes into account a single canonical point \b x. * * The cache is constructed for each dimension and each level up to \b max_levels, * the values of the Lagrange polynomials are computed in two passes resulting in O(n) operations. * - \b num_dimensions is the number of dimensions to consider * - \b max_levels indicates how many levels to consider in each direction, * heavily anisotropic grids require only a few levels for the "less important" directions * - \b rule is the wrapper of the Global grid that contains information about number of points per level * and the actual nodes with the pre-computed Lagrange coefficients * - \b holds the coordinates of the canonical point to cache */ CacheLagrange(int num_dimensions, const std::vector &max_levels, const OneDimensionalWrapper &rule, const double x[]) : cache(std::vector>(num_dimensions, std::vector())), offsets(rule.getPointsCount()){ for(int dim=0; dim=0; j--){ c *= (x - nodes[j+1]); cc[j] *= c * coeff[j]; } } //! \brief Return the Lagrange cache for given \b dimension, \b level and offset local to the level T getLagrange(int dimension, int level, int local) const{ return cache[dimension][offsets[level] + local]; } protected: /*! * \brief Stores the values of the Lagrange polynomias for each dimension and each level * * cache[i] corresponds to the i-th dimension. * The i-th vector has the values of the Lagrange polynomials going level by level, * so the value of the Lagrange polynomial for dimension i at level l with local offset j * will be cache[i][ offsets[l] + j ] */ std::vector> cache; //! \brief Stores the offsets for each level within each dimension std::vector offsets; }; /*! * \internal * \ingroup TasmanianAcceleration * \brief Cache that holds the derivatives of 1D Lagrange polynomials. Uses the same interface as CacheLagrange. * \endinternal */ template class CacheLagrangeDerivative { public: /*! * \brief Constructor that takes into account a single canonical point \b x. * * The cache is constructed for each dimension and each level up to \b max_levels, * the derivatives of the Lagrange polynomials are computed in two passes resulting in O(n) operations. * - \b num_dimensions is the number of dimensions to consider * - \b max_levels indicates how many levels to consider in each direction, * heavily anisotropic grids require only a few levels for the "less important" directions * - \b rule is the wrapper of the Global grid that contains information about number of points per level * and the actual nodes with the pre-computed Lagrange coefficients * - \b holds the coordinates of the canonical point to cache */ CacheLagrangeDerivative(int num_dimensions, const std::vector &max_levels, const OneDimensionalWrapper &rule, const double x[]) : cache(std::vector>(num_dimensions, std::vector())), offsets(rule.getPointsCount()) { for(int dim=0; dim aux_f(num_points), aux_g(num_points); cc[0] = (rule.getRule() == rule_clenshawcurtis0) ? 2.0 * x : 0.0; aux_f[0] = (rule.getRule() == rule_clenshawcurtis0) ? x * x - 1.0 : 1.0; aux_g[num_points-1] = 1.0; for(int i=1; i=0; i--) { diff_gj = aux_g[i+1] + diff_gj * (x - nodes[i+1]); cc[i] = coeff[i] * (cc[i] * aux_g[i] + aux_f[i] * diff_gj); } } //! \brief Return the Lagrange derivative cache for given \b dimension, \b level and offset local to the level T getLagrangeDerivative(int dimension, int level, int local) const { return cache[dimension][offsets[level] + local]; } protected: //! \brief See CacheLagrange::cache std::vector> cache; //! \brief See CacheLagrange::offsets std::vector offsets; }; } #endif TASMANIAN-8.1/SparseGrids/tsgCoreOneDimensional.cpp000066400000000000000000000711031470551176200220740ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_CORE_ONE_DIMENSIONAL_CPP #define __TSG_CORE_ONE_DIMENSIONAL_CPP #include "tsgCoreOneDimensional.hpp" #include "tsgIOHelpers.hpp" namespace TasGrid{ template void CustomTabulated::write(std::ostream &ofs) const{ if (iomode == mode_ascii){ // format is messy here ofs << "description: " << description.c_str() << std::endl; ofs << "levels: " << num_levels << std::endl; for(int i=0; i void CustomTabulated::read(std::istream &is){ if (iomode == mode_ascii){ // messy format chosen for better human readability, hard to template and generalize std::string T; char dummy; is >> T; if (!(T.compare("description:") == 0)){ throw std::invalid_argument("ERROR: wrong file format of custom tables on line 1"); } is.get(dummy); description = std::string(); getline(is, description); is >> T; if (!(T.compare("levels:") == 0)){ throw std::invalid_argument("ERROR: wrong file format of custom tables on line 2"); } is >> num_levels; num_nodes.resize(num_levels); precision.resize(num_levels); for(int i=0; i> num_nodes[i] >> precision[i]; nodes.resize(num_levels); weights.resize(num_levels); for(int l=0; l> w >> *x++; } }else{ int num_description = 0; is.read((char*) &num_description, sizeof(int)); std::vector desc((size_t) num_description+1); is.read(desc.data(), num_description); desc[num_description] = '\0'; description = desc.data(); is.read((char*) &num_levels, sizeof(int)); num_nodes.resize(num_levels); precision.resize(num_levels); is.read((char*) num_nodes.data(), num_levels * sizeof(int)); is.read((char*) precision.data(), num_levels * sizeof(int)); nodes.resize(num_levels); weights.resize(num_levels); for(int l=0; l(std::ostream &) const; template void CustomTabulated::write(std::ostream &) const; template void CustomTabulated::read(std::istream &is); template void CustomTabulated::read(std::istream &is); void CustomTabulated::read(const char* filename){ std::ifstream ifs; ifs.open(filename); if (!ifs){ std::string message = "Could not open the custom rule file: "; message += filename; throw std::invalid_argument(message); } read(ifs); ifs.close(); } void CustomTabulated::getWeightsNodes(int level, std::vector &w, std::vector &x) const{ w = weights[level]; x = nodes[level]; } void CustomTabulated::getWeightsNodes(int level, double w[], double x[]) const{ std::copy(weights[level].begin(), weights[level].end(), w); std::copy(nodes[level].begin(), nodes[level].end(), x); } const char* CustomTabulated::getDescription() const{ return description.c_str(); } CustomTabulated getSubrules(CustomTabulated &ct, int start_index, int stride, std::string description) { std::vector sub_num_nodes, sub_precision; std::vector> sub_weights, sub_nodes; for (int level=start_index; level w, x; sub_num_nodes.push_back(ct.getNumPoints(level)); sub_precision.push_back(ct.getQExact(level)); sub_weights.emplace_back(std::vector()); sub_nodes.emplace_back(std::vector()); ct.getWeightsNodes(level, sub_weights.back(), sub_nodes.back()); } return CustomTabulated(std::move(sub_num_nodes), std::move(sub_precision), std::move(sub_nodes), std::move(sub_weights), std::move(description)); } int OneDimensionalMeta::getNumPoints(int level, TypeOneDRule rule){ int lcc; switch (rule){ case rule_chebyshev: case rule_gausslegendre: case rule_leja: case rule_rleja: case rule_rlejashifted: case rule_maxlebesgue: case rule_minlebesgue: case rule_mindelta: case rule_gausschebyshev1: case rule_gausschebyshev2: case rule_gaussgegenbauer: case rule_gaussjacobi: case rule_gausslaguerre: case rule_gausshermite: return level+1; case rule_chebyshevodd: case rule_gausslegendreodd: case rule_lejaodd: case rule_rlejaodd: case rule_maxlebesgueodd: case rule_minlebesgueodd: case rule_mindeltaodd: case rule_gausschebyshev1odd: case rule_gausschebyshev2odd: case rule_gaussgegenbauerodd: case rule_gaussjacobiodd: case rule_gausslaguerreodd: case rule_gausshermiteodd: return 2*level+1; case rule_rlejashiftedeven: return 2*(level + 1); case rule_rlejashifteddouble: return Maths::pow2(level+1); case rule_clenshawcurtis0: case rule_gausspatterson: return Maths::pow2(level+1) - 1; case rule_clenshawcurtis: return (level == 0) ? 1 : (Maths::pow2(level) + 1); case rule_rlejadouble2: if (level < 3){ return getNumPoints(level, rule_clenshawcurtis); }; lcc = 2 + (level-3)/2; return (getNumPoints(lcc,rule_clenshawcurtis) + ((getNumPoints(lcc+1,rule_clenshawcurtis)-getNumPoints(lcc,rule_clenshawcurtis))/2) * ((level-3)%2 +1)); case rule_rlejadouble4: if (level < 3){ return getNumPoints(level, rule_clenshawcurtis); }; lcc = 2 + (level-3)/4; return (getNumPoints(lcc,rule_clenshawcurtis) + ((getNumPoints(lcc+1,rule_clenshawcurtis)-getNumPoints(lcc,rule_clenshawcurtis))/4) * ((level-3)%4 +1)); case rule_fejer2: return Maths::pow2(level+1) - 1; case rule_fourier: return Maths::pow3(level); default: return level; // should not be called, but compiler complains for the lack of return/default } } int OneDimensionalMeta::getIExact(int level, TypeOneDRule rule){ switch (rule){ case rule_chebyshev: case rule_gausslegendre: case rule_leja: case rule_rleja: case rule_rlejashifted: case rule_maxlebesgue: case rule_minlebesgue: case rule_mindelta: case rule_gausschebyshev1: case rule_gausschebyshev2: case rule_gaussgegenbauer: case rule_gaussjacobi: case rule_gausslaguerre: case rule_gausshermite: return level; case rule_chebyshevodd: case rule_gausslegendreodd: case rule_lejaodd: case rule_rlejaodd: case rule_maxlebesgueodd: case rule_minlebesgueodd: case rule_mindeltaodd: case rule_gausschebyshev1odd: case rule_gausschebyshev2odd: case rule_gaussgegenbauerodd: case rule_gaussjacobiodd: case rule_gausslaguerreodd: case rule_gausshermiteodd: return 2*level; case rule_rlejashiftedeven: return 2*level + 1; case rule_rlejashifteddouble: return Maths::pow2(level+1) -1; case rule_gausspatterson: case rule_fejer2: return Maths::pow2(level+1) -2; case rule_clenshawcurtis: return (level > 0) ? Maths::pow2(level) : 0; case rule_clenshawcurtis0: return Maths::pow2(level+1) +1; case rule_rlejadouble2: return getNumPoints(level,rule_rlejadouble2)-1; case rule_rlejadouble4: return getNumPoints(level,rule_rlejadouble4)-1; case rule_fourier: return (Maths::pow3(level)-1)/2; default: return level; // should not be called, but compiler complains for the lack of return/default } } int OneDimensionalMeta::getQExact(int level, TypeOneDRule rule){ switch (rule){ case rule_chebyshevodd: case rule_gausslegendre: case rule_gausschebyshev1: case rule_gausschebyshev2: case rule_gaussgegenbauer: case rule_gaussjacobi: case rule_gausslaguerre: case rule_gausshermite: return 2*level+1; case rule_gausschebyshev1odd: case rule_gausschebyshev2odd: case rule_gaussgegenbauerodd: case rule_gausshermiteodd: case rule_gaussjacobiodd: case rule_gausslaguerreodd: case rule_gausslegendreodd: return 4*level+1; case rule_rleja: case rule_rlejashifted: return level; case rule_leja: case rule_maxlebesgue: case rule_minlebesgue: case rule_mindelta: return ((level == 0) ? 1 : level) + ((level == 2) ? 1 : 0); case rule_lejaodd: case rule_maxlebesgueodd: case rule_minlebesgueodd: case rule_mindeltaodd: return ((level == 0) ? 1 : 2*level) + ((level == 1) ? 1 : 0); case rule_rlejaodd: return 2*level; case rule_rlejashiftedeven: return 2*level; case rule_rlejashifteddouble: return Maths::pow2(level+1) -1; case rule_gausspatterson: return (level == 0) ? 1 : (3 * Maths::pow2(level) - 1); case rule_clenshawcurtis: return (level == 0) ? 1 : (Maths::pow2(level) + 1); case rule_clenshawcurtis0: return (level == 0) ? 1 : (Maths::pow2(level+1) + 1); case rule_chebyshev: return level+1; case rule_rlejadouble2: return getNumPoints(level,rule_rlejadouble2); case rule_rlejadouble4: return getNumPoints(level,rule_rlejadouble4)-1; case rule_fejer2: return Maths::pow2(level+1) - 1; case rule_fourier: return (Maths::pow3(level)-1)/2; default: return level; // should not be called, but compiler complains for the lack of return/default } } bool OneDimensionalMeta::isNonNested(TypeOneDRule rule){ return ((rule == rule_chebyshev) || (rule == rule_chebyshevodd) || (rule == rule_gausslegendre) || (rule == rule_gausslegendreodd) || (rule == rule_gausschebyshev1) || (rule == rule_gausschebyshev1odd) || (rule == rule_gausschebyshev2) || (rule == rule_gausschebyshev2odd) || (rule == rule_gaussgegenbauer) || (rule == rule_gaussgegenbauerodd) || (rule == rule_gaussjacobi) || (rule == rule_gaussjacobiodd) || (rule == rule_gausslaguerre) || (rule == rule_gausslaguerreodd) || (rule == rule_gausshermite) || (rule == rule_gausshermiteodd) || (rule == rule_customtabulated)); } bool OneDimensionalMeta::isSequence(TypeOneDRule rule){ return ((rule == rule_leja) || (rule == rule_rleja) || (rule == rule_rlejashifted) || (rule == rule_maxlebesgue) || (rule == rule_minlebesgue) || (rule == rule_mindelta)); } bool OneDimensionalMeta::isGlobal(TypeOneDRule rule){ return !((rule == rule_semilocalp) || (rule == rule_localp0) || (rule == rule_localp) || (rule == rule_localpb) || (rule == rule_wavelet) || (rule == rule_fourier) || (rule == rule_none)); } bool OneDimensionalMeta::isSingleNodeGrowth(TypeOneDRule rule){ return ((rule == rule_leja) || (rule == rule_rleja) || (rule == rule_rlejashifted) || (rule == rule_maxlebesgue) || (rule == rule_minlebesgue) || (rule == rule_mindelta) || (rule == rule_gausslegendre) || (rule == rule_gausschebyshev1) || (rule == rule_gausschebyshev2) || (rule == rule_gaussgegenbauer) || (rule == rule_gaussjacobi) || (rule == rule_gausslaguerre) || (rule == rule_gausshermite)); } bool OneDimensionalMeta::isLocalPolynomial(TypeOneDRule rule){ return ((rule == rule_localp) || (rule == rule_localp0) || (rule == rule_semilocalp) || (rule == rule_localpb)); } bool OneDimensionalMeta::isWavelet(TypeOneDRule rule){ // used by the tasgrid wrapper return (rule == rule_wavelet); } bool OneDimensionalMeta::isFourier(TypeOneDRule rule){ // used by the tasgrid wrapper return (rule == rule_fourier); } const char* OneDimensionalMeta::getHumanString(TypeOneDRule rule){ switch (rule){ case rule_clenshawcurtis: return "Clenshaw-Curtis"; case rule_clenshawcurtis0: return "Clenshaw-Curtis zero boundary conditions"; case rule_chebyshev: return "Chebyshev"; case rule_chebyshevodd: return "Chebyshev, odd rules only"; case rule_gausslegendre: return "Gauss-Legendre"; case rule_gausslegendreodd: return "Gauss-Legendre, odd rules only"; case rule_gausspatterson: return "Gauss-Patterson"; case rule_leja: return "Leja"; case rule_lejaodd: return "Leja, odd rules only"; case rule_rleja: return "R-Leja"; case rule_rlejaodd: return "R-Leja odd rules only"; case rule_rlejadouble2: return "R-Leja doubling every 2 levels"; case rule_rlejadouble4: return "R-Leja doubling every 4 levels"; case rule_rlejashifted: return "R-Leja shifted by 1/2"; case rule_rlejashiftedeven: return "R-Leja shifted by 1/2, even rules only"; case rule_rlejashifteddouble: return "R-Leja shifted by 1/2, doubling rule"; case rule_maxlebesgue: return "Maximum of the Lebesgue function"; case rule_maxlebesgueodd: return "Maximum of the Lebesgue function, odd rules only"; case rule_minlebesgue: return "Minimum (greedy) of the Lebesgue constant"; case rule_minlebesgueodd: return "Minimum (greedy) of the Lebesgue constant, odd rules only"; case rule_mindelta: return "Minimum surplus operator norm"; case rule_mindeltaodd: return "Minimum surplus operator norm, odd rules only"; case rule_gausschebyshev1: return "Gauss-Chebyshev of type 1"; case rule_gausschebyshev1odd: return "Gauss-Chebyshev of type 1, odd rules only"; case rule_gausschebyshev2: return "Gauss-Chebyshev of type 2"; case rule_gausschebyshev2odd: return "Gauss-Chebyshev of type 2, odd rules only"; case rule_fejer2: return "Fejer type 2"; case rule_gaussgegenbauer: return "Gauss-Gegenbauer"; case rule_gaussgegenbauerodd: return "Gauss-Gegenbauer, odd rules only"; case rule_gaussjacobi: return "Gauss-Jacobi"; case rule_gaussjacobiodd: return "Gauss-Jacobi, odd rules only"; case rule_gausslaguerre: return "Gauss-Laguerre"; case rule_gausslaguerreodd: return "Gauss-Laguerre, odd rules only"; case rule_gausshermite: return "Gauss-Hermite"; case rule_gausshermiteodd: return "Gauss-Hermite, odd rules only"; case rule_customtabulated: return "Custom rule"; case rule_localp: return "Local polynomials"; case rule_localp0: return "Local polynomials zero boundary conditions"; case rule_localpb: return "Local polynomials focused nodes on the boundary"; case rule_semilocalp: return "Semi-Local polynomials"; case rule_wavelet: return "Wavelets"; case rule_fourier: return "Fourier / trigonometric"; default: return "unknown"; } } // Gauss-Legendre void OneDimensionalNodes::getGaussLegendre(int m, std::vector &w, std::vector &x){ double mu0 = 2.0; std::vector diag(m, 0.0), off_diag(m-1); for(int i=0; i &w, std::vector &x){ // get Clanshaw-Curtis quadrature points w.resize(m); x.resize(m); int i, j; double b; if (m == 1){ w[0] = 2.0; x[0] = 0.0; return; }; for(i=0; i &w, std::vector &x){ w.resize(m); x.resize(m); for(int i=0; i &w, std::vector &x){ w.resize(m); x.resize(m); for(int i=0; i &w, std::vector &x, double alpha, double beta){ double ab = alpha + beta; double mu0 = pow(2.0, 1.0 + ab) * tgamma(alpha + 1.0) * tgamma(beta + 1.0) / tgamma(2.0 + ab); std::vector diag(m), off_diag(m-1); diag[0] = (beta - alpha) / (2.0 + ab); if (m > 1) { off_diag[0] = std::sqrt(4.0 * (1.0 + alpha) * (1.0 + beta) / ((3.0 + ab) * (2.0 + ab) * (2.0 + ab))); for(int i=1; i &w, std::vector &x, double alpha){ double mu0 = tgamma(0.5 * (alpha + 1.0)); std::vector diag(m, 0.0), off_diag(m-1); for(int i=0; i &w, std::vector &x, double alpha){ double mu0 = tgamma(alpha + 1.0); std::vector diag(m), off_diag(m-1); for(int i=0; i OneDimensionalNodes::getClenshawCurtisNodes(int level){ int n = OneDimensionalMeta::getNumPoints(level, rule_clenshawcurtis); std::vector nodes(n, 0.0); if (level > 0){ nodes[1] = -1.0; nodes[2] = 1.0; int count = 3; for(int l=2; l<=level; l++){ n = OneDimensionalMeta::getNumPoints(l, rule_clenshawcurtis); for(int i=1; i>= 1){ l++; }; ieffective = (1 + 2 *(point - OneDimensionalMeta::getNumPoints(l-1, rule_clenshawcurtis))) * (n-1) / (1 << l); } double weight = 1.0; double theta = ((double) ieffective) * Maths::pi / ((double) (n-1)); for(int j=1; j<(n-1)/2; j++){ weight -= 2.0 * std::cos(2.0 * j * theta) / ((double) (4*j*j - 1)); } weight -= std::cos(2.0 * (n-1) * theta / 2.0) / ((double) (n*n - 2*n)); weight /= (double) (n-1); if ((point != 1) && (point != 2)){ weight *= 2.0; } return weight; } // Clenshaw-Curtis-Zero std::vector OneDimensionalNodes::getClenshawCurtisNodesZero(int level){ int n = OneDimensionalMeta::getNumPoints(level+1, rule_clenshawcurtis); std::vector nodes(n-2, 0.0); if (level > 0){ int count = 1; for(int l=2; l<=level+1; l++){ n = OneDimensionalMeta::getNumPoints(l, rule_clenshawcurtis); for(int i=1; i>= 1){ l++; }; ieffective = (1 + 2 *(point + 2 - OneDimensionalMeta::getNumPoints(l-1, rule_clenshawcurtis))) * (n-1) / (1 << l); } double weight = 1.0; double theta = ((double) ieffective) * Maths::pi / ((double) (n-1)); for(int j=1; j<(n-1)/2; j++){ weight -= 2.0 * std::cos(2.0 * j * theta) / ((double) (4*j*j - 1)); } weight -= std::cos(2.0 * (n-1) * theta / 2.0) / ((double) (n*n - 2*n)); weight /= (double) (n-1); weight *= 2.0; return weight; } // Fejer-2 std::vector OneDimensionalNodes::getFejer2Nodes(int level){ int n = OneDimensionalMeta::getNumPoints(level, rule_fejer2); std::vector nodes(n, 0.0); if (level > 0){ int count = 1; for(int l=2; l<=level+1; l++){ n = OneDimensionalMeta::getNumPoints(l, rule_clenshawcurtis); for(int i=1; i>= 1){ l++; }; z = (1 << (level-l))-1; ieffective = z + (point - OneDimensionalMeta::getNumPoints(l-1, rule_fejer2)) * ((n-1) / (1 << (l))+1); } double weight = 1.0; double theta = ((double) (n-ieffective)) * Maths::pi / ((double) (n+1)); for(int j=1; j<=(n-1)/2; j++){ weight -= 2.0 * std::cos(2.0 * j * theta) / ((double) (4*j*j - 1)); } weight -= std::cos(((double) (n+1)) * theta) / ((double) (n)); weight *= 2.0 / ((double) (n+1)); return weight; } std::vector OneDimensionalNodes::getRLeja(int n){ std::vector nodes(n, 0.0); if (n > 1){ nodes[1] = Maths::pi; } if (n > 2){ nodes[2] = 0.5 * Maths::pi; } for(int i=3; i 2){ nodes[2] = 0.0; } // not sure which version is better, starting at 0 or starting at 1 return nodes; } std::vector OneDimensionalNodes::getRLejaCentered(int n){ std::vector nodes = getRLeja(n); nodes[0] = 0.0; if (n > 1){ nodes[1] = 1.0; } if (n > 2){ nodes[2] = -1.0; } return nodes; } std::vector OneDimensionalNodes::getRLejaShifted(int n){ std::vector nodes(n, -0.5); if (n > 1){ nodes[1] = 0.5; } for(int i=2; i OneDimensionalNodes::getFourierNodes(int level) { int n = OneDimensionalMeta::getNumPoints(level, rule_fourier); std::vector nodes(n, 0.0); if(level > 0){ nodes[1] = 1.0/3.0; nodes[2] = 2.0/3.0; } size_t c = 3; for(int l=2; l<=level; l++) { n = OneDimensionalMeta::getNumPoints(l, rule_fourier); for(int i=1; i CustomTabulated(std::istream &is, iomode) : CustomTabulated(){ if (std::is_same::value) read(is); else read(is); } //! \brief Assume ownership of existing data instead of reading from a file. CustomTabulated(std::vector &&cnum_nodes, std::vector &&cprecision, std::vector> &&cnodes, std::vector> &&cweights, std::string &&cdescription) : num_levels(cnum_nodes.size()), num_nodes(std::move(cnum_nodes)), precision(std::move(cprecision)), nodes(std::move(cnodes)), weights(std::move(cweights)), description(std::move(cdescription)) {} //! \brief Write to an already open ASCII/binary file, used in conjunction with \b GlobalGrid::write() template void write(std::ostream &os) const; //! \brief Read from an already open ASCII/binary file, used in conjunction with \b GlobalGrid::read() template void read(std::istream &is); //! \brief Read from a custom user provided ASCII file, see the file-format section. void read(const char* filename); //! \brief Returns the number of loaded levels. int getNumLevels() const{ return num_levels; } //! \brief Returns the number of points associated with the selected \b level. int getNumPoints(int level) const{ checkLevel(level, "number of points"); return num_nodes[level]; } //! \brief Return the exactness of the interpolation rule at \b level, usually one less than the number of points. int getIExact(int level) const{ checkLevel(level, "i-exactness"); return num_nodes[level] -1; } //! \brief Return the exactness of the integration/quadrature rule at \b level, provided by the user in the custom file. int getQExact(int level) const{ checkLevel(level, "q-exactness"); return precision[level]; } //! \brief Get the points \b x and quadrature weights \b w associated with the rule at the \b level. void getWeightsNodes(int level, std::vector &w, std::vector &x) const; //! \brief Overload that writes to an array directly rather than a container. For interface purposes mostly, e.g. Python. void getWeightsNodes(int level, double w[], double x[]) const; //! \brief Returns the user provided human readable description string. const char* getDescription() const; protected: //! \brief Throws a std::rumtime_error() if the given \b level is more than the stored levels, \b op is used to report the failed operation. void checkLevel(int level, std::string const &op) const{ if (level >= num_levels) throw std::runtime_error(std::string("ERROR: needed custom rule ") + op + " with level " + std::to_string(level) + " but the table ends at " + std::to_string(num_levels - 1)); } private: int num_levels; std::vector num_nodes; std::vector precision; std::vector> nodes; std::vector> weights; std::string description; }; /*! \internal * \ingroup TasmanianCoreOneDimensional * \brief Generates a subset of rules as a CustomTabulated object. The subset has a short description string given by * \b description and takes the levels of the input \b ct starting from level \b start_index with distance \b stride between * consecutive levels. * * \endinternal */ CustomTabulated getSubrules(CustomTabulated &ct, int start_index, int stride, std::string description); //! \internal //! \brief Metadata for one dimensional rules, number of points, exactness, I/O, etc. //! \ingroup TasmanianCoreOneDimensional namespace OneDimensionalMeta{ //! \brief Return the number of points for the \b rule at the \b level, includes all global rules. int getNumPoints(int level, TypeOneDRule rule); //! \brief Return the exactness of the interpolation \b rule at the \b level, includes all global rules. int getIExact(int level, TypeOneDRule rule); //! \brief Return the exactness of the integration/quadrature \b rule at the \b level, includes all global rules. int getQExact(int level, TypeOneDRule rule); //! \brief Return \b True if the \b rule does not have nested nodes, e.g., gauss-legendre. bool isNonNested(TypeOneDRule rule); //! \brief Return \b True if the \b rule is nested and has single-node growth, fit for \b GridSequence, e.g., leja. bool isSequence(TypeOneDRule rule); //! \brief Return \b True if the \b rule has basis with Lagrange polynomials with global support, fit for \b GridGlobal, e.g., clenshaw-curtis. bool isGlobal(TypeOneDRule rule); //! \brief Return \b True if the \b rule grows by one point per level. bool isSingleNodeGrowth(TypeOneDRule rule); //! \brief Return \b True if the \b rule has polynomial basis with local support, fit for \b GridLocalPolynomial, e.g., localp. bool isLocalPolynomial(TypeOneDRule rule); //! \brief Return \b True if the \b rule has wavelet basis with local support. bool isWavelet(TypeOneDRule rule); //! \brief Return \b True if the \b rule has trigonometric basis. bool isFourier(TypeOneDRule rule); //! \brief Map the enumerate to a human readable string, used in \b printStats(). const char* getHumanString(TypeOneDRule rule); //! \brief Identifies the general contour, linear \b type_level, log-corrected \b type_curved, or hyperbolic \b type_hyperbolic. //! The types of index selection are divided into contour type and selection type. //! All types are combination between the two, i.e., type_iptotal uses interpolation polynomial selection and linear contour. //! This function reduces the type to one of the three level contours, which simplifies the if-statements in many places. //! Note: the tensor rules are a special case and are not considered in this function. inline TypeDepth getControurType(TypeDepth type){ if ((type == type_level) || (type == type_iptotal) || (type == type_qptotal)){ return type_level; }else if ((type == type_curved) || (type == type_ipcurved) || (type == type_qpcurved)){ return type_curved; }else{ return type_hyperbolic; } } //! \brief Returns true if the \b type indicates exactness with respect to raw levels. inline bool isExactLevel(TypeDepth type){ return (type == type_level) || (type == type_curved) || (type == type_hyperbolic) || (type == type_tensor); } //! \brief Returns true if the \b type indicates exactness with respect to interpolation. inline bool isExactInterpolation(TypeDepth type){ return (type == type_iptotal) || (type == type_ipcurved) || (type == type_iphyperbolic) || (type == type_iptensor); } //! \brief Returns true if the \b type indicates exactness with respect to integration. inline bool isExactQuadrature(TypeDepth type){ return (type == type_qptotal) || (type == type_qpcurved) || (type == type_qphyperbolic) || (type == type_qptensor); } //! \brief Identifies the selection type, level \b type_level, interpolation \b type_iptotal, or quadrature \b type_qptotal. //! Similar to \b getControurType(), return what selection is considered, simple levels or interpolation/quadrature polynomial space. inline TypeDepth getSelectionType(TypeDepth type){ if ((type == type_level) || (type == type_curved) || (type == type_hyperbolic)){ return type_level; }else if ((type == type_iptotal) || (type == type_ipcurved) || (type == type_iphyperbolic)){ return type_iptotal; }else{ return type_qptotal; } } //! \brief Return \b True if the multi-index selection type has log-correction term (need to use floating point indexing). inline bool isTypeCurved(TypeDepth type){ return (getControurType(type) == type_curved); } } //! \internal //! \brief Contains algorithms for generating Gauss,Chebyshev, and Fourier nodes and weights. //! \ingroup TasmanianCoreOneDimensional namespace OneDimensionalNodes{ // non-nested rules //! \brief Generate Gauss-Legendre weights \b w and points \b x for (input) number of points \b m. void getGaussLegendre(int m, std::vector &w, std::vector &x); //! \brief Generate Chebyshev weights \b w and points \b x for (input) number of points \b m. void getChebyshev(int m, std::vector &w, std::vector &x); //! \brief Generate Gauss-Chebyshev type 1 weights \b w and points \b x for (input) number of points \b m. void getGaussChebyshev1(int m, std::vector &w, std::vector &x); //! \brief Generate Gauss-Chebyshev type 2 weights \b w and points \b x for (input) number of points \b m. void getGaussChebyshev2(int m, std::vector &w, std::vector &x); //! \brief Generate Gauss-Jacobi weights \b w and points \b x for (input) number of points \b m, using parameters \b alpha and \b beta. void getGaussJacobi(int m, std::vector &w, std::vector &x, double alpha, double beta); //! \brief Generate Gauss-Hermite weights \b w and points \b x for (input) number of points \b m, using parameters \b alpha void getGaussHermite(int m, std::vector &w, std::vector &x, double alpha); //! \brief Generate Gauss-Laguerre weights \b w and points \b x for (input) number of points \b m, using parameters \b alpha void getGaussLaguerre(int m, std::vector &w, std::vector &x, double alpha); // nested rules //! \brief Generate Clenshaw-Curtis \b nodes for the \b level. std::vector getClenshawCurtisNodes(int level); //! \brief Return the Clenshaw-Curtis weight for the \b level and node indexed by \b point. double getClenshawCurtisWeight(int level, int point); //! \brief Generate Clenshaw-Curtis zero-boundary condition \b nodes for the \b level. std::vector getClenshawCurtisNodesZero(int level); // assuming zero boundary //! \brief Return the Clenshaw-Curtis zero-boundary condition weight for the \b level and node indexed by \b point. double getClenshawCurtisWeightZero(int level, int point); // assuming zero boundary //! \brief Generate Fejer type 2 \b nodes for the \b level. std::vector getFejer2Nodes(int level); //! \brief Return the Fejer type 2 weight for the \b level and node indexed by \b point. double getFejer2Weight(int level, int point); //! \brief Generate the first \b n R-Leja \b nodes, starting with 1, -1, 0, ... std::vector getRLeja(int n); //! \brief Generate the first \b n R-Leja \b nodes, starting with 0, 1, -1, ... std::vector getRLejaCentered(int n); //! \brief Generate the first \b n R-Leja \b nodes, starting with -0.5, 0.5, ... std::vector getRLejaShifted(int n); //! \brief Generate the Fourier \b nodes for the given \b level, uniformly distributed points with right-most point omitted due to periodicity. std::vector getFourierNodes(int level); } } #endif TASMANIAN-8.1/SparseGrids/tsgCudaBasisEvaluations.hpp000066400000000000000000000706561470551176200224510ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_CUDA_BASIS_EVALUATIONS_HPP #define __TASMANIAN_SPARSE_GRID_CUDA_BASIS_EVALUATIONS_HPP #include "TasmanianConfig.hpp" #ifdef Tasmanian_ENABLE_CUDA #include #include // Global grids require atomic add #include #if __CUDA_ARCH__ >= 600 #include // atomic add for doubles was added in arch 6.0 #else #ifdef __CUDA_ARCH__ // borrowed from https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#atomic-functions // implements less efficient (software) atomic add that works on archs before 6.0 __device__ inline double atomicAdd(double* address, double val) { unsigned long long int* address_as_ull = (unsigned long long int*)address; unsigned long long int old = *address_as_ull, assumed; do { assumed = old; old = atomicCAS(address_as_ull, assumed, __double_as_longlong(val + __longlong_as_double(assumed))); // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN) } while (assumed != old); return __longlong_as_double(old); } #endif #endif #endif #ifdef Tasmanian_ENABLE_HIP #ifndef __HIP_PLATFORM_HCC__ #define __HIP_PLATFORM_HCC__ #endif #include #include #endif namespace TasGrid{ // convert a transformed domain to a canonical one // gpu_trans_a and gpu_trans_b are the rate and shifts (precomputed on the cpu) // size_a is the size of the gpu_trans_a and gpu_trans_b, note that the rates and shifts are repeated in some integer multiple of dims to allow contiguous access // num_x is the number of points that need converstion // T is the input type, i.e., the type of the transformed points // C is the output type, i.e., the type of the canonical points and the rate and shift arrays // THREADS can be as high as possible (e.g., 1024), but the algorithm will fail if num_dimensions exceeds THREADS (which is highly unlikely) // also see AccelerationDomainTransform::AccelerationDomainTransform(), where gpu_trans_a/b are encoded and size_a is computed template // transformed and canonical types __global__ void tasgpu_transformed_to_canonical(int dims, int num_x, int size_a, const C *gpu_trans_a, const C *gpu_trans_b, const T *gpu_x_transformed, T *gpu_x_canonical){ extern __shared__ C rate[]; C *shift = &(rate[size_a]); int i = threadIdx.x; while(i < size_a){ rate[i] = gpu_trans_a[i]; shift[i] = gpu_trans_b[i]; i += THREADS; } __syncthreads(); int k = blockIdx.x * THREADS + threadIdx.x; int k_stride = THREADS * gridDim.x; i = k % size_a; while(k < (dims * num_x)){ gpu_x_canonical[k] = ((T) gpu_x_transformed[k]) * rate[i] - shift[i]; k += k_stride; i = k % size_a; } } // convert (-1, 1) to (0, 1) template __global__ void tasgpu_m11_to_01(int num_points, T *gpu_x){ int i = blockIdx.x * THREADS + threadIdx.x; while (i < num_points){ T v = gpu_x[i]; v += 1.0; v /= 2.0; gpu_x[i] = v; i += THREADS * gridDim.x; } } __device__ inline double linear_boundary_wavelet(double x){ if (fabs(x + 0.5) > 0.5) return 0.0; if (x <= -0.75){ return 0.75 * (7.0 * x + 6.0); }else if (x <= -0.5){ return -0.25 * (11.0 * x + 6.0); }else{ return 0.25 * x; } } __device__ inline double linear_central_wavelet(double x){ if (fabs(x + 0.25) > 0.75) return 0.0; if (x <= -0.5){ return -0.5 * x - 0.5; }else if (x >= 0.0){ return 0.5 * x - 0.25; }else if (x <= -0.25){ return 4.0 * x + 1.75; }else{ return -4.0 * x - 0.25; } } // evaluates a single basis function // syncronize with GridLocalPolynomial::encodeSupportForGPU() for the meaning of negative support // in essense, the formula is that feval = 1 - |x - node| / support, or feval = 1 - (x - node)^2 / support^2 // there are exceptions for the constant function on level 0, the "half linear" functions on level 1 for localp, and the global functions on level 1 for semi-localp template __device__ inline T tasgpu_devalpwpoly_feval(const double x, const double node, const double support){ // <- arrays are cached T v; if (rule == rule_localp){ if (order == 0){ v = (fabs(x - node) > support) ? 0.0 : 1.0; }else if (order == 1){ v = 1.0 - fabs(x - node) / support; if (support == -1.0) v = 1.0; if (v < 0.0) v = 0.0; }else if (order == 2){ v = x - node; v *= v; v = 1.0 - v / support; if (support == -1.0) v = 1.0; if (support == -2.0) v = -x; if (support == -3.0) v = x; if (v < 0.0) v = 0.0; } }else if (rule == rule_localp0){ if (order == 1){ v = 1.0 - fabs(x - node) / support; if (v < 0.0) v = 0.0; }else if (order == 2){ v = x - node; v *= v; v = 1.0 - v / support; if (v < 0.0) v = 0.0; } }else if (rule == rule_localpb){ if (order == 1){ v = 1.0 - fabs(x - node) / support; if (v < 0.0) v = 0.0; }else if (order == 2){ if (support == -2.0){ v = 1.0 + fabs(x - node) / support; }else{ v = x - node; v *= v; v = 1.0 - v / support; if (v < 0.0) v = 0.0; } } }else if (rule == rule_semilocalp){ if (order == 2){ v = x - node; v *= v; v = 1.0 - v / support; if (v < 0.0) v = 0.0; if (support == -1.0) v = 1.0; if (support == -4.0) v = 0.5 * x * (x - 1.0); if (support == -5.0) v = 0.5 * x * (x + 1.0); } }else{ // wavelet, node = scale, support = shift and encodes the type of wavelet // sync with RuleWavelet::getShiftScale() if (support == -1.0){ // level 0, using basic hat-functions v = 1.0 - fabs(x - node); if (v < 0.0) v = 0.0; }else if (support == -2.0){ // left boundary v = linear_boundary_wavelet(node * (x + 1.0) - 1.0); }else if (support == -3.0){ // right boundary v = linear_boundary_wavelet(node * (1.0 - x) - 1.); }else{ v = linear_central_wavelet(node * (x + 1.0) - 1.0 - support); } } //printf(" v = %1.4e order = %d x = %1.4e node = %1.4e supp = %1.4e \n", v, order, x, node, support); return v; } // evaluates the sparse grid functions for localp0, local0 and semilocalp rules using a DENSE algorithm // use with MAX_DIM = 64 and SHORT = 32 or MAX_DIM = 32 and SHORT = 64 // dims is num_dimensions, this kernel cannot handle more than 64-dimensions, which is plenty for a sparse grid // grid blocks take 32 points each, cache the points, then iteratively take successive blocks of 32 x values (32 x dims) // each block of 32 gpu_x values is cached and used to form a 32 by 32 block of the values matrix // thus, the nodes and support are reused and only the smaller array of x vlaues is read repeatedly (each thread-block reads the whole array once) // gpu_x is canonical x (same format as CPU, dim-major format) // use 1D thread-blocks with (num_points / 32) blocks template // rule: localp0, localp, semilocalp __global__ void tasgpu_devalpwpoly(int dims, int num_x, int num_points, const T *gpu_x, const T *gpu_nodes, const T *gpu_support, T *gpu_y){ __shared__ T cache_nodes[SHORT * MAX_DIM]; __shared__ T cache_support[SHORT * MAX_DIM]; __shared__ T cache_x[SHORT * MAX_DIM]; int height = threadIdx.x % SHORT; // threads are oranized logically in a square of size SHORT by SHORT int swidth = threadIdx.x / SHORT; // height and swidth are the indexes of this thread in the block (relates to num_points and num_x respectively) int max_p = dims * num_points; // maximum number of entries in nodes and support, avoid reading beyond int max_x = dims * num_x; // maximum number of entries in gpu_x, avoid reading beyond int id_p = SHORT * blockIdx.x; while(id_p < num_points){ // cache support and nodes (reused a lot) int i = threadIdx.x; while(i < SHORT * dims){ if (id_p * dims + i < max_p){ cache_nodes[(i % dims) * SHORT + (i / dims)] = gpu_nodes[id_p * dims + i]; cache_support[(i % dims) * SHORT + (i / dims)] = gpu_support[id_p * dims + i]; } i += 1024; } __syncthreads(); int id_x = 0; while(id_x < num_x){ // cache gpu_x (used only for this block) i = threadIdx.x; while(i < SHORT * dims){ if (id_x * dims + i < max_x) cache_x[i] = gpu_x[id_x * dims + i]; i += 1024; } __syncthreads(); T v = 1.0; for(int j=0; j(cache_x[swidth * dims + j], cache_nodes[height + SHORT * j], cache_support[height + SHORT * j]); } if ((id_p + height < num_points) && (id_x + swidth < num_x)) gpu_y[(id_x + swidth) * num_points + (id_p + height)] = v; __syncthreads(); id_x += (1024 / SHORT); } id_p += SHORT * gridDim.x; } } // evaluates a single basis function, for use with sparse evaluations template __device__ inline T tasgpu_devalpwpoly_basis_multid(int dims, int i, int ip, const T *x, const T *nodes, const T *support){ T p = 1.0; for(int j=0; j(this_x, this_node, this_supp); } return p; } // the refinement process for piece wise constant rule (pwc) should cover a region larger than the regular support // this is needed since refinement has to be performed between existing nodes and not just within the support // see: Miroslav Stoyanov, "Adaptive sparse grid construction in a context of local anisotropy and multiple hierarchical parents" // Sparse Grids with Applications, 2016 (pre-print) template __device__ inline T tasgpu_devalpwpoly_support_pwc_multid(int dims, int i, int ip, const T *x, const T *nodes, const T *support){ T p = 1.0; for(int j=0; j 2.0 * support[ip * dims + j]) ? 0.0 : 1.0); } return p; } // essentially the same as local polynomial evaluate, just repeated for many threads, this is SPARSE algorithm // at 64 threads and 46 TOPLEVEL, the 48K of shared memory is ehxausted with 4 byte integer // note that the resolution at level 46 is 1 / 2^46 = O(1.E-13), which is comparative to the precision, i.e., never use more than 46 levels, makes no sense // the kernel is called twice with fill false and then true // false only counts the non-zeros, sindx and svals are ignored // true fills the non-zeros in sindx and svals, sindx and svals must be pre-allocated template __global__ void tasgpu_devalpwpoly_sparse(int dims, int num_x, const T *x, const T *nodes, const T *support, const int *hpntr, const int *hindx, int num_roots, const int *roots, int *spntr, int *sindx, T *svals){ __shared__ int mcount[TOPLEVEL][THREADS]; __shared__ int mstop[TOPLEVEL][THREADS]; int i = blockIdx.x * THREADS + threadIdx.x; while(i < num_x){ int c = 0; if (fill) c = spntr[i]; //printf("i = %d c = %d\n", i, c); for(int r=0; r 0){ p = tasgpu_devalpwpoly_basis_multid(dims, i, ip, x, nodes, support); }else{ p = tasgpu_devalpwpoly_support_pwc_multid(dims, i, ip, x, nodes, support); } if (p != 0.0){ if (fill){ sindx[c] = ip; if (order == 0){ p = tasgpu_devalpwpoly_basis_multid(dims, i, ip, x, nodes, support);; } svals[c] = p; } c++; int current = 0; mstop[0][threadIdx.x] = hpntr[ip + 1]; mcount[0][threadIdx.x] = hpntr[ip]; while(mcount[0][threadIdx.x] < mstop[0][threadIdx.x]){ if (mcount[current][threadIdx.x] < mstop[current][threadIdx.x]){ ip = hindx[mcount[current][threadIdx.x]]; if (order > 0){ p = tasgpu_devalpwpoly_basis_multid(dims, i, ip, x, nodes, support); }else{ p = tasgpu_devalpwpoly_support_pwc_multid(dims, i, ip, x, nodes, support); } if (p != 0.0){ if (fill){ sindx[c] = ip; if (order == 0){ p = tasgpu_devalpwpoly_basis_multid(dims, i, ip, x, nodes, support);; } svals[c] = p; } c++; current++; mstop[current][threadIdx.x] = hpntr[ip + 1]; mcount[current][threadIdx.x] = hpntr[ip]; }else{ mcount[current][threadIdx.x]++; } }else{ current--; mcount[current][threadIdx.x]++; } } } } if (!fill){ spntr[i+1] = c; } i += gridDim.x * THREADS; } } // call with THREADS > dims, THREADS > max_num_nodes // creates a cache data structure for evaluating basis functions with sequence grids // dims and num_x are number of dimensions and number of x points, gpuX holds the points in the same format as the CPU version // nodes and coeffs are the 1D sequence nodes and the normalizing hierarchical Newton coefficients (same as the GPU version) // max_num_nodes is the maxumum number of nodes in any direction (needed to correctly capture the cache) // the result (i.e., cache) has block form, each of the offsets give cumulative index of the next block // each bock has size num_nodes[d] X num_x, holding the values of the Newton polynomials associated with x in direction d // blocks do not have identical structure, due to anisotropy block sizes can vary // num_nodes is the maximum number of nodes in the corresponding direction // cache is contiguous in the direction of x template __global__ void tasgpu_dseq_build_cache(int dims, int num_x, const T *gpuX, const T *nodes, const T *coeffs, int max_num_nodes, const int *offsets, const int *num_nodes, T *result){ __shared__ int soffsets[THREADS]; // cache offsets, nodes and coefficients __shared__ T snodes[THREADS]; __shared__ T scoeffs[THREADS]; if (threadIdx.x < dims) soffsets[threadIdx.x] = offsets[threadIdx.x]; if (threadIdx.x < max_num_nodes){ snodes[threadIdx.x] = nodes[threadIdx.x]; scoeffs[threadIdx.x] = coeffs[threadIdx.x]; } __syncthreads(); int i = blockIdx.x * THREADS + threadIdx.x; while(i < num_x){ for(int d=0; d __global__ void tasgpu_dseq_eval_sharedpoints(int dims, int num_x, int num_points, const int *points, const int *offsets, const T *cache, T *result){ __shared__ int cpoints[1024 / SHORT][SHORT]; // uses only 32 * 32 * 4 = 4K of 48K shared memory int height = threadIdx.x % SHORT; // threads are oranized logically in a square of size SHORT by SHORT int swidth = threadIdx.x / SHORT; // height and swidth are the indexes of this thread in the block (relates to num_points and num_x respectively) int id_p = SHORT * blockIdx.x; while(id_p < num_points){ if ((swidth < dims) && (id_p + height < num_points)){ cpoints[swidth][height] = points[swidth * num_points + id_p + height]; // load a block of points } __syncthreads(); if (id_p + height < num_points){ int id_x = swidth; while(id_x < num_x){ // loop over the x-values // read and multiply from cached data strucutre, but uses only L2/1 cache, no shared GPU memory double v = cache[num_x * cpoints[0][height] + id_x]; for(int j=1; j dims // creates a cache data structure for evaluating basis functions with fourier grids // dims and num_x are number of dimensions and number of x points, gpuX holds the points in the same format as the CPU version // each bock has size 2 X num_nodes[d] X num_x, holding the values of the Fourier basis associated with x in direction d // the result (i.e., cache) has block form, each of the offsets give cumulative index of the next block // blocks do not have identical structure, due to anisotropy block sizes can vary // num_nodes is the maximum number of nodes in the corresponding direction (i.e., maximum power) // cache is contiguous in the direction of x template __global__ void tasgpu_dfor_build_cache(int dims, int num_x, const T *gpuX, const int *offsets, const int *num_nodes, T *result){ __shared__ int soffsets[THREADS]; // cache offsets, nodes and coefficients if (threadIdx.x < dims) soffsets[threadIdx.x] = offsets[threadIdx.x]; __syncthreads(); int i = blockIdx.x * THREADS + threadIdx.x; while(i < num_x){ for(int d=0; d __global__ void tasgpu_dfor_eval_sharedpoints(int dims, int num_x, int num_points, const int *points, const int *offsets, const T *cache, T *wreal, T *wimag){ __shared__ int cpoints[1024 / SHORT][SHORT]; // uses only 32 * 32 * 4 = 4K of 48K shared memory int height = threadIdx.x % SHORT; // threads are oranized logically in a square of size SHORT by SHORT int swidth = threadIdx.x / SHORT; // height and swidth are the indexes of this thread in the block (relates to num_points and num_x respectively) int id_p = SHORT * blockIdx.x; while(id_p < num_points){ if ((swidth < dims) && (id_p + height < num_points)){ cpoints[swidth][height] = points[swidth * num_points + id_p + height]; // load a block of points } __syncthreads(); if (id_p + height < num_points){ int id_x = swidth; while(id_x < num_x){ // loop over the x-values // read and multiply from cached data strucutre, but uses only L2/1 cache, no shared GPU memory T vreal = cache[2 * num_x * cpoints[0][height] + id_x]; T vimag = cache[2 * num_x * cpoints[0][height] + num_x + id_x]; for(int j=1; j __global__ void tasgpu_dglo_build_cache(int num_dims, int num_x, int cache_lda, T const *gpu_x, T const *nodes, T const *coeff, int const *nodes_per_level, int const *offset_per_level, int const *dim_offsets, int const *map_dimension, int const *map_level, T *cache){ int blkid = blockIdx.x; while(blkid < cache_lda){ // loop over all dim-level pairs int idx = threadIdx.x; int dim = map_dimension[blkid]; // get the dim for this thread block int lvl = map_level[blkid]; // get the level for the thread block int num_nodes = nodes_per_level[lvl]; int opl = offset_per_level[lvl]; while(idx < num_x){ // loop over all num_x T x = gpu_x[idx * num_dims + dim]; // get the local x int cache_offset = (dim_offsets[dim] + opl) * num_x; T c = 1.0; cache[cache_offset + idx] = c; for(int j=0; j0; j--){ c *= (nested) ? (x - nodes[j]) : (x - nodes[opl + j]); cache[cache_offset + idx] *= c * coeff[opl + j - 1]; cache_offset -= num_x; } idx += NUM_THREADS; } blkid += gridDim.x; } } template __global__ void tasgpu_dglo_eval_zero(int size, T *result){ int i = blockIdx.x * THREADS + threadIdx.x; while(i < size){ result[i] = 0.0; i += gridDim.x * THREADS; } } template __global__ void tasgpu_dglo_eval_sharedpoints(int num_dims, int num_x, int loop_lda, int result_lda, T const *cache, T const *tweights, int const *offset_per_level, int const *dim_offsets, int const *active_tensors, int const *active_num_points, int const *map_tensor, int const *map_index, int const *map_reference, T *result){ int blkid = blockIdx.x; while(blkid < loop_lda){ // loop over all dim-level pairs int idx = threadIdx.x; int tensor = map_tensor[blkid]; // get the tensor for this thread block int ref = map_reference[blkid]; int toff = tensor * num_dims; while(idx < num_x){ // loop over all num_x int index = map_index[blkid]; // get the index for the thread block T w = 1.0; for(int j=num_dims-1; j>=0; j--){ w *= cache[(dim_offsets[j] + offset_per_level[active_tensors[toff + j]] + index % active_num_points[toff + j]) * num_x + idx]; index /= active_num_points[toff + j]; } atomicAdd(&result[idx * result_lda + ref], tweights[tensor] * w); idx += NUM_THREADS; } blkid += gridDim.x; } } } #endif TASMANIAN-8.1/SparseGrids/tsgCudaKernels.cu000066400000000000000000000570751470551176200204200ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_CUDA_KERNELS_CU #define __TASMANIAN_SPARSE_GRID_CUDA_KERNELS_CU #include "tsgAcceleratedDataStructures.hpp" #include "tsgCudaLinearAlgebra.hpp" #include "tsgCudaBasisEvaluations.hpp" // several kernels assume a linear distribution of the threads and can be executed with "practically unlimited" number of threads // thus we can set this to the CUDA max number of threads, based on the current cuda version constexpr int _MAX_CUDA_THREADS = 1024; // max number of blocks per grid direction constexpr int _MAX_CUDA_BLOCKS = 65535; /* * Create a 1-D CUDA thread grid using the total_threads and number of threads per block. * Basically, computes the number of blocks but no more than _MAX_CUDA_BLOCKS. */ struct ThreadGrid1d{ // Compute the threads and blocks. ThreadGrid1d(long long total_threads, long long num_per_block) : threads(static_cast(num_per_block)), blocks(static_cast(std::min(total_threads / threads + ((total_threads % threads == 0) ? 0 : 1), static_cast(_MAX_CUDA_BLOCKS)))) {} // number of threads int const threads; // number of blocks int const blocks; }; namespace TasGrid{ template void TasGpu::dtrans2can(AccelerationContext const*, bool use01, int dims, int num_x, int pad_size, double const *gpu_trans_a, double const *gpu_trans_b, T const *gpu_x_transformed, T *gpu_x_canonical){ int num_blocks = (num_x * dims) / _MAX_CUDA_THREADS + (((num_x * dims) % _MAX_CUDA_THREADS == 0) ? 0 : 1); if (num_blocks >= _MAX_CUDA_BLOCKS) num_blocks = _MAX_CUDA_BLOCKS; tasgpu_transformed_to_canonical<<>>(dims, num_x, pad_size, gpu_trans_a, gpu_trans_b, gpu_x_transformed, gpu_x_canonical); if (use01) tasgpu_m11_to_01<<>>(dims * num_x, gpu_x_canonical); } template void TasGpu::dtrans2can(AccelerationContext const*, bool, int, int, int, double const*, double const*, double const*, double*); template void TasGpu::dtrans2can(AccelerationContext const*, bool, int, int, int, double const*, double const*, float const*, float*); // local polynomial basis functions, DENSE algorithm template void TasGpu::devalpwpoly(AccelerationContext const*, int order, TypeOneDRule rule, int dims, int num_x, int num_points, const T *gpu_x, const T *gpu_nodes, const T *gpu_support, T *gpu_y){ // each block thread runs 1024 threads and processes 32 points (or basis functions) int num_blocks = (num_points / 32) + ((num_points % 32 == 0) ? 0 : 1); // order == 1 is considered "default" so that the compiler doesn't complain about missing default statement // semilocalp cannot have order less than 2, only rule_localp can have order 0 (this gets overwrittein in makeLocalPolynomialGrid()) if (rule == rule_localp){ switch(order){ case 0: tasgpu_devalpwpoly<<>>(dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; case 2: tasgpu_devalpwpoly<<>>(dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; default: tasgpu_devalpwpoly<<>>(dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } }else if (rule == rule_localp0){ switch(order){ case 2: tasgpu_devalpwpoly<<>>(dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; default: tasgpu_devalpwpoly<<>>(dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } }else if (rule == rule_localpb){ switch(order){ case 2: tasgpu_devalpwpoly<<>>(dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; default: tasgpu_devalpwpoly<<>>(dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } }else if (rule == rule_semilocalp){ tasgpu_devalpwpoly<<>>(dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); }else{ // rule == wavelet tasgpu_devalpwpoly<<>>(dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } } template void TasGpu::devalpwpoly(AccelerationContext const*, int, TypeOneDRule, int, int, int, const double*, const double*, const double*, double*); template void TasGpu::devalpwpoly(AccelerationContext const*, int, TypeOneDRule, int, int, int, const float*, const float*, const float*, float*); // there is a switch statement that realizes templates for each combination of rule/order // make one function that covers that switch, the rest is passed from devalpwpoly_sparse template inline void devalpwpoly_sparse_realize_rule_order(AccelerationContext const*, int order, TypeOneDRule rule, int dims, int num_x, const T *x, const T *nodes, const T *support, const int *hpntr, const int *hindx, int num_roots, const int *roots, int *spntr, int *sindx, T *svals){ int num_blocks = num_x / THREADS + ((num_x % THREADS == 0) ? 0 : 1); if (num_blocks >= _MAX_CUDA_BLOCKS) num_blocks = _MAX_CUDA_BLOCKS; if (rule == rule_localp){ switch(order){ case 0: tasgpu_devalpwpoly_sparse<<>> (dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; case 2: tasgpu_devalpwpoly_sparse<<>> (dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; default: tasgpu_devalpwpoly_sparse<<>> (dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } }else if (rule == rule_localp0){ switch(order){ case 2: tasgpu_devalpwpoly_sparse<<>> (dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; default: tasgpu_devalpwpoly_sparse<<>> (dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } }else if (rule == rule_localpb){ switch(order){ case 2: tasgpu_devalpwpoly_sparse<<>> (dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; default: tasgpu_devalpwpoly_sparse<<>> (dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } }else{ // rule == rule_semilocalp tasgpu_devalpwpoly_sparse<<>> (dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } } // local polynomial basis functions, SPARSE algorithm (2 passes, one pass to compue the non-zeros and one pass to evaluate) template void TasGpu::devalpwpoly_sparse(AccelerationContext const *acc, int order, TypeOneDRule rule, int dims, int num_x, const T *gpu_x, const GpuVector &gpu_nodes, const GpuVector &gpu_support, const GpuVector &gpu_hpntr, const GpuVector &gpu_hindx, const GpuVector &gpu_hroots, GpuVector &gpu_spntr, GpuVector &gpu_sindx, GpuVector &gpu_svals){ gpu_spntr.resize(acc, num_x + 1); // call with fill == false to count the non-zeros per row of the matrix devalpwpoly_sparse_realize_rule_order (acc, order, rule, dims, num_x, gpu_x, gpu_nodes.data(), gpu_support.data(), gpu_hpntr.data(), gpu_hindx.data(), (int) gpu_hroots.size(), gpu_hroots.data(), gpu_spntr.data(), 0, 0); std::vector cpu_spntr; gpu_spntr.unload(acc, cpu_spntr); cpu_spntr[0] = 0; int nz = 0; for(auto &i : cpu_spntr){ i += nz; nz = i; } gpu_spntr.load(acc, cpu_spntr); gpu_sindx.resize(acc, nz); gpu_svals.resize(acc, nz); // call with fill == true to load the non-zeros devalpwpoly_sparse_realize_rule_order (acc, order, rule, dims, num_x, gpu_x, gpu_nodes.data(), gpu_support.data(), gpu_hpntr.data(), gpu_hindx.data(), (int) gpu_hroots.size(), gpu_hroots.data(), gpu_spntr.data(), gpu_sindx.data(), gpu_svals.data()); } template void TasGpu::devalpwpoly_sparse(AccelerationContext const*, int, TypeOneDRule, int, int, const double*, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, GpuVector&, GpuVector&, GpuVector&); template void TasGpu::devalpwpoly_sparse(AccelerationContext const*, int, TypeOneDRule, int, int, const float*, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, GpuVector&, GpuVector&, GpuVector&); // Sequence Grid basis evaluations template void TasGpu::devalseq(AccelerationContext const *acc, int dims, int num_x, const std::vector &max_levels, const T *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, T *gpu_result){ std::vector offsets(dims); offsets[0] = 0; for(int d=1; d gpu_offsets(acc, offsets); GpuVector cache1D(acc, num_total); int num_blocks = num_x / _MAX_CUDA_THREADS + ((num_x % _MAX_CUDA_THREADS == 0) ? 0 : 1); tasgpu_dseq_build_cache<<>> (dims, num_x, gpu_x, nodes.data(), coeffs.data(), maxl+1, gpu_offsets.data(), num_nodes.data(), cache1D.data()); num_blocks = num_x / 32 + ((num_x % 32 == 0) ? 0 : 1); tasgpu_dseq_eval_sharedpoints<<>> (dims, num_x, (int) points.size() / dims, points.data(), gpu_offsets.data(), cache1D.data(), gpu_result); } template void TasGpu::devalseq(AccelerationContext const*, int dims, int num_x, const std::vector &max_levels, const double *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, double *gpu_result); template void TasGpu::devalseq(AccelerationContext const*, int dims, int num_x, const std::vector &max_levels, const float *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, float *gpu_result); // Fourier Grid basis evaluations template void TasGpu::devalfor(AccelerationContext const *acc, int dims, int num_x, const std::vector &max_levels, const T *gpu_x, const GpuVector &num_nodes, const GpuVector &points, T *gpu_wreal, typename GpuVector::value_type *gpu_wimag){ std::vector max_nodes(dims); for(int j=0; j offsets(dims); offsets[0] = 0; for(int d=1; d gpu_offsets(acc, offsets); GpuVector cache1D(acc, num_total); int num_blocks = num_x / _MAX_CUDA_THREADS + ((num_x % _MAX_CUDA_THREADS == 0) ? 0 : 1); tasgpu_dfor_build_cache<<>> (dims, num_x, gpu_x, gpu_offsets.data(), num_nodes.data(), cache1D.data()); num_blocks = num_x / 32 + ((num_x % 32 == 0) ? 0 : 1); if (gpu_wimag == 0){ tasgpu_dfor_eval_sharedpoints<<>> (dims, num_x, (int) points.size() / dims, points.data(), gpu_offsets.data(), cache1D.data(), gpu_wreal, 0); }else{ tasgpu_dfor_eval_sharedpoints<<>> (dims, num_x, (int) points.size() / dims, points.data(), gpu_offsets.data(), cache1D.data(), gpu_wreal, gpu_wimag); } } template void TasGpu::devalfor(AccelerationContext const*, int, int, const std::vector&, const double*, const GpuVector&, const GpuVector&, double*, double*); template void TasGpu::devalfor(AccelerationContext const*, int, int, const std::vector&, const float*, const GpuVector&, const GpuVector&, float*, float*); template void TasGpu::devalglo(AccelerationContext const *acc, bool is_nested, bool is_clenshawcurtis0, int dims, int num_x, int num_p, int num_basis, T const *gpu_x, GpuVector const &nodes, GpuVector const &coeff, GpuVector const &tensor_weights, GpuVector const &nodes_per_level, GpuVector const &offset_per_level, GpuVector const &map_dimension, GpuVector const &map_level, GpuVector const &active_tensors, GpuVector const &active_num_points, GpuVector const &dim_offsets, GpuVector const &map_tensor, GpuVector const &map_index, GpuVector const &map_reference, T *gpu_result){ GpuVector cache(acc, num_x, num_basis); int num_blocks = (int) map_dimension.size(); if (num_blocks >= _MAX_CUDA_BLOCKS) num_blocks = _MAX_CUDA_BLOCKS; if (is_nested){ if (is_clenshawcurtis0){ tasgpu_dglo_build_cache<<>> (dims, num_x, (int) map_dimension.size(), gpu_x, nodes.data(), coeff.data(), nodes_per_level.data(), offset_per_level.data(), dim_offsets.data(), map_dimension.data(), map_level.data(), cache.data()); }else{ tasgpu_dglo_build_cache<<>> (dims, num_x, (int) map_dimension.size(), gpu_x, nodes.data(), coeff.data(), nodes_per_level.data(), offset_per_level.data(), dim_offsets.data(), map_dimension.data(), map_level.data(), cache.data()); } }else{ tasgpu_dglo_build_cache<<>> (dims, num_x, (int) map_dimension.size(), gpu_x, nodes.data(), coeff.data(), nodes_per_level.data(), offset_per_level.data(), dim_offsets.data(), map_dimension.data(), map_level.data(), cache.data()); } int mat_size = num_x * num_p; num_blocks = num_x / _MAX_CUDA_THREADS + ((mat_size % _MAX_CUDA_THREADS == 0) ? 0 : 1); if (num_blocks >= _MAX_CUDA_BLOCKS) num_blocks = _MAX_CUDA_BLOCKS; tasgpu_dglo_eval_zero<<>>(mat_size, gpu_result); num_blocks = (int) map_tensor.size(); if (num_blocks >= _MAX_CUDA_BLOCKS) num_blocks = _MAX_CUDA_BLOCKS; tasgpu_dglo_eval_sharedpoints<<>> (dims, num_x, (int) map_tensor.size(), num_p, cache.data(), tensor_weights.data(), offset_per_level.data(), dim_offsets.data(), active_tensors.data(), active_num_points.data(), map_tensor.data(), map_index.data(), map_reference.data(), gpu_result); } template void TasGpu::devalglo(AccelerationContext const*, bool, bool, int, int, int, int, double const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, double*); template void TasGpu::devalglo(AccelerationContext const*, bool, bool, int, int, int, int, float const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, float*); void TasGpu::fillDataGPU(AccelerationContext const*, double value, long long n, long long stride, double data[]){ if (stride == 1){ ThreadGrid1d tgrid(n, _MAX_CUDA_THREADS); tascuda_vfill<<>>(n, data, value); }else{ ThreadGrid1d tgrid(n, 32); tascuda_sfill<<>>(n, stride, data, value); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Linear Algebra //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef __TASMANIAN_COMPILE_FALLBACK_CUDA_KERNELS__ void TasCUDA::cudaDgemm(int M, int N, int K, const double *gpu_a, const double *gpu_b, double *gpu_c){ // gpu_c = gpu_a * gpu_b, gpu_c is M by N int blocks = (N / 96) + (((N % 96) == 0) ? 0 : 1); blocks *= (M / 96) + (((M % 96) == 0) ? 0 : 1); while(blocks > _MAX_CUDA_BLOCKS) blocks = _MAX_CUDA_BLOCKS; tasgpu_cudaTgemm<<>>(M, N, K, gpu_a, gpu_b, gpu_c); } void TasCUDA::cudaSparseMatmul(int M, int N, int num_nz, const int* gpu_spntr, const int* gpu_sindx, const double* gpu_svals, const double *gpu_B, double *gpu_C){ int blocks = M / 64 + ((M % 64 == 0) ? 0 : 1); tasgpu_sparse_matmul<<>>(M, N, num_nz, gpu_spntr, gpu_sindx, gpu_svals, gpu_B, gpu_C); } void TasCUDA::cudaSparseVecDenseMat(int M, int N, int num_nz, const double *A, const int *indx, const double *vals, double *C){ int num_blocks = N / _MAX_CUDA_THREADS + ((N % _MAX_CUDA_THREADS == 0) ? 0 : 1); if (num_blocks< _MAX_CUDA_BLOCKS){ tasgpu_sparse_matveci<<>>(M, N, num_nz, A, indx, vals, C); }else{ num_blocks = N / (2 * _MAX_CUDA_THREADS) + ((N % (2 * _MAX_CUDA_THREADS) == 0) ? 0 : 1); if (num_blocks< _MAX_CUDA_BLOCKS){ tasgpu_sparse_matveci<<>>(M, N, num_nz, A, indx, vals, C); }else{ num_blocks = N / (3 * _MAX_CUDA_THREADS) + ((N % (3 * _MAX_CUDA_THREADS) == 0) ? 0 : 1); if (num_blocks< _MAX_CUDA_BLOCKS){ tasgpu_sparse_matveci<<>>(M, N, num_nz, A, indx, vals, C); } } } } void TasCUDA::convert_sparse_to_dense(int num_rows, int num_columns, const int *pntr, const int *indx, const double *vals, double *destination){ int n = num_rows * num_columns; int num_blocks = n / _MAX_CUDA_THREADS + ((n % _MAX_CUDA_THREADS == 0) ? 0 : 1); if (num_blocks >= _MAX_CUDA_BLOCKS) num_blocks = _MAX_CUDA_BLOCKS; tascuda_fill<<>>(n, 0.0, destination); num_blocks = num_rows; if (num_blocks >= _MAX_CUDA_BLOCKS) num_blocks = _MAX_CUDA_BLOCKS; tascuda_sparse_to_dense<<>>(num_rows, num_columns, pntr, indx, vals, destination); } #endif } #endif TASMANIAN-8.1/SparseGrids/tsgCudaLinearAlgebra.hpp000066400000000000000000000330171470551176200216530ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_CUDA_LINEAR_ALGEBRA_HPP #define __TASMANIAN_SPARSE_GRID_CUDA_LINEAR_ALGEBRA_HPP #include "TasmanianConfig.hpp" namespace TasGrid{ // NOTE: the kernels here were used for testing and debugging (and place holders before using the MAGMA library) // presently, none of the templates are instantiated unless __TASMANIAN_COMPILE_FALLBACK_CUDA_KERNELS__ is defined in tsgAcceleratedDataStructures.hpp (TasCUDA namespace) // only works with SHORT = 32 and BLOCK = 96 // using blocks, block in C has dims BLOCK by BLOCK = 3 * SHORT by 3 * SHORT, // blocks of A and B are both BLOCK by SHORT or 3 * SHORT by SHORT template // assuming ratio LONG = 2 * SHORT, THREADS = SHORT * SHORT __global__ void tasgpu_cudaTgemm(int M, int N, int K, const T *gpu_a, const T *gpu_b, T *gpu_c){ __shared__ T cache_a[SHORT * BLOCK]; __shared__ T cache_b[SHORT * BLOCK]; int num_blocks_m = M / BLOCK + ((M % BLOCK == 0) ? 0 : 1); // number of total blocks in M direction int num_blocks_n = N / BLOCK + ((N % BLOCK == 0) ? 0 : 1); // number of total blocks in N direction num_blocks_m *= num_blocks_n; // num_blocks_m is never used without a product to num_blocks_n int block = blockIdx.x; // keep track of the block being processed (each thread block takes on a block of C) int height = threadIdx.x % SHORT; // threads are oranized logivally in a square of size SHORT by SHORT (relates to M and K) int swidth = threadIdx.x / SHORT; // height and swidth are the indexes of this thread in the block (relates to N and K) // sequential threads are adjacent in height (column major logic) while(block < num_blocks_m){ // find out the current matrix block for this block of threads int block_m = block / num_blocks_n; int maxM = BLOCK; if (block_m * BLOCK + maxM > M) maxM = M - block_m * BLOCK; int block_n = block % num_blocks_n; int maxN = BLOCK; if (block_n * BLOCK + maxN > N) maxN = N - block_n * BLOCK; int offsetm = block_m * BLOCK; // identify row/column of C // prepare cache in c T c11 = 0.0; T c12 = 0.0; T c13 = 0.0; T c21 = 0.0; T c22 = 0.0; T c23 = 0.0; T c31 = 0.0; T c32 = 0.0; T c33 = 0.0; for(int k=0; k K) maxK = K - k; // preload A if (swidth < maxK){ int offseta = k * M + swidth * M + offsetm + height; int offsetl = swidth * SHORT + height; if (height < maxM) cache_a[offsetl] = gpu_a[offseta]; offseta += SHORT; offsetl += SHORT*SHORT; if (height + SHORT < maxM) cache_a[offsetl] = gpu_a[offseta]; offseta += SHORT; offsetl += SHORT*SHORT; if (height + 2*SHORT < maxM) cache_a[offsetl] = gpu_a[offseta]; } // preload B if (height < maxK){ // start of the block + k processes so far + local column + the k for this thread int offsetb = block_n * BLOCK * K + k + swidth * K + height; if (swidth < maxN) cache_b[threadIdx.x] = gpu_b[offsetb]; offsetb += SHORT * K; if (swidth + SHORT < maxN) cache_b[SHORT * SHORT + threadIdx.x] = gpu_b[offsetb]; offsetb += SHORT * K; if (swidth + 2 * SHORT < maxN) cache_b[2 * SHORT * SHORT + threadIdx.x] = gpu_b[offsetb]; } __syncthreads(); for(int local_k=0; local_k < maxK; local_k++){ // process the 4 blocks of C int offa = height + local_k * SHORT; // position in a cache int offb = swidth * SHORT + local_k; // position in b cache // for memory in cache a threads read adjacent values, in bache b all threads read one valua at a time T val = cache_a[offa]; c11 += val * cache_b[offb]; c12 += val * cache_b[offb + SHORT * SHORT]; c13 += val * cache_b[offb + 2 * SHORT * SHORT]; val = cache_a[offa + SHORT * SHORT]; c21 += val * cache_b[offb]; c22 += val * cache_b[offb + SHORT * SHORT]; c23 += val * cache_b[offb + 2 * SHORT * SHORT]; val = cache_a[offa + 2 * SHORT * SHORT]; c31 += val * cache_b[offb]; c32 += val * cache_b[offb + SHORT * SHORT]; c33 += val * cache_b[offb + 2 * SHORT * SHORT]; } __syncthreads(); } // write into C // block column thread column block row thread row offsetm = block_n * BLOCK * M + swidth * M + block_m * BLOCK + height; if (swidth < maxN){ if (height < maxM) gpu_c[offsetm ] = c11; if (height + SHORT < maxM) gpu_c[offsetm + SHORT] = c21; if (height + 2 * SHORT < maxM) gpu_c[offsetm + 2 * SHORT] = c31; } offsetm += SHORT * M; // jump by short columns if (swidth + SHORT < maxN){ if (height < maxM) gpu_c[offsetm ] = c12; if (height + SHORT < maxM) gpu_c[offsetm + SHORT] = c22; if (height + 2 * SHORT < maxM) gpu_c[offsetm + 2 * SHORT] = c32; } offsetm += SHORT * M; // jump by short columns if (swidth + 2 * SHORT < maxN){ if (height < maxM) gpu_c[offsetm ] = c13; if (height + SHORT < maxM) gpu_c[offsetm + SHORT] = c23; if (height + 2 * SHORT < maxM) gpu_c[offsetm + 2 * SHORT] = c33; } block += gridDim.x; } } // sparse matrix-matrix multiply // C = A * B, where A is in sparse row compressed form (pntr, indx, vals, num_nz) and C and B are in row major formats, C is M by N // threads in a block first cache indx and vals, then use the cached values to march accross N incrementing C contiguously template __global__ void tasgpu_sparse_matmul(int M, int N, int num_nz, const int *pntr, const int *indx, const T *vals, const T *B, T *C){ __shared__ int cache_indx[THREADS]; __shared__ T cache_vals[THREADS]; int i = blockIdx.x * THREADS; // indexes rows of C while(i < M){ int endi = i + THREADS; if (endi > M) endi = M; while(i < endi){ int c = threadIdx.x; // indexes columns of C while(c < N){ // intialize C to zero C[i * N + c] = 0.0; c += THREADS; } int offj = pntr[i]; while(offj < pntr[i+1]){ if (offj + threadIdx.x < num_nz){ // cache a bunch of indx and vals cache_indx[threadIdx.x] = indx[offj + threadIdx.x]; cache_vals[threadIdx.x] = vals[offj + threadIdx.x]; } __syncthreads(); int endj = THREADS; if (offj + endj > pntr[i+1]) endj = pntr[i+1] - offj; // stop when reaching the next i c = threadIdx.x; while(c < N){ T sum = 0.0; for(int j=0; j __global__ void tasgpu_sparse_matveci(int M, int num_nz, const T *A, const int *indx, const T *vals, T *C){ __shared__ int cache_indx[THREADS]; __shared__ T cache_vals[THREADS]; int m = blockIdx.x * THREADS * NBLOCKS ; // m is the starting row of the block while(m < M){ m += threadIdx.x; // the row this thread will process T c1 = 0.0; T c2 = 0.0; T c3 = 0.0; T c4 = 0.0; int sparse_row = 0; while(sparse_row < num_nz){ int maxVals = THREADS; if (sparse_row + maxVals > num_nz) maxVals = num_nz - sparse_row; // cache the vector if (threadIdx.x < maxVals){ cache_indx[threadIdx.x] = indx[sparse_row + threadIdx.x]; cache_vals[threadIdx.x] = vals[sparse_row + threadIdx.x]; } __syncthreads(); for(int i=0; i 1) c2 += val * A[off + THREADS]; if (NBLOCKS > 2) c3 += val * A[off + 2 * THREADS]; if (NBLOCKS > 3) c4 += val * A[off + 3 * THREADS]; } sparse_row += THREADS; __syncthreads(); } C[m] = c1; if (NBLOCKS > 1) C[m + THREADS] = c2; if (NBLOCKS > 2) C[m + 2 * THREADS] = c3; if (NBLOCKS > 3) C[m + 3 * THREADS] = c4; m -= threadIdx.x; m += THREADS * NBLOCKS; // the starting row of this block } } // convert sparse matrix to dense format template __global__ void tascuda_fill(int n, T value, T *destination){ int k = blockIdx.x * THREADS + threadIdx.x; T v = value; while(k < n){ destination[k] = v; k += gridDim.x * THREADS; } } // assumes row-compressed and row-major format // each block processes one row, so use few threads per block // this ensures contiguous read from indx and vals template __global__ void tascuda_sparse_to_dense(int num_rows, int num_columns, const int *pntr, const int *indx, const T *vals, T *destination){ int i = blockIdx.x; // row to process while(i < num_rows){ // each block processes one row int j = pntr[i]; int endj = pntr[i+1]; int offi = i * num_columns; while(j < endj){ if (j + threadIdx.x < endj){ destination[offi + indx[j + threadIdx.x]] = vals[j + threadIdx.x]; } j += THREADS; } i += gridDim.x; } } // vector fill, fills the data with the given value template __global__ void tascuda_vfill(long long n, T data[], T value){ long long k = blockIdx.x * THREADS + threadIdx.x; while(k < n){ data[k] = value; k += gridDim.x * THREADS; } } // strided fill, fills the data with the given value and stride template __global__ void tascuda_sfill(long long n, long long stride, T data[], T value){ long long k = blockIdx.x * THREADS + threadIdx.x; while(k < n){ data[k * stride] = value; k += gridDim.x * THREADS; } } } #endif TASMANIAN-8.1/SparseGrids/tsgCudaLoadStructures.hpp000066400000000000000000000144771470551176200221570ustar00rootroot00000000000000/* * Copyright (c) 2018, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_CUDA_LOAD_STRUCTS_HPP #define __TASMANIAN_SPARSE_CUDA_LOAD_STRUCTS_HPP #include "tsgAcceleratedDataStructures.hpp" namespace TasGrid{ #ifndef __TASMANIAN_DOXYGEN_SKIP /*! * \internal * \brief Wrapper structure for the vectors needed by Global grid CUDA methods. * * \endinternal */ template struct CudaGlobalData{ GpuVector values; // cache stage int num_basis; // number of 1d basis functions GpuVector nodes; GpuVector coeff; GpuVector nodes_per_level; GpuVector offset_per_level; // non-nested case nodes, always used for coefficients GpuVector map_dimension; GpuVector map_level; // compute stage GpuVector tensor_weights; GpuVector active_tensors; GpuVector active_num_points; GpuVector dim_offsets; // relates to the cache GpuVector map_tensor; GpuVector map_index; GpuVector map_reference; void clearNodes(){ num_basis = 0; nodes.clear(); coeff.clear(); nodes_per_level.clear(); offset_per_level.clear(); map_dimension.clear(); map_level.clear(); tensor_weights.clear(); active_tensors.clear(); active_num_points.clear(); dim_offsets.clear(); map_tensor.clear(); map_index.clear(); map_reference.clear(); } }; //! \internal //! \brief Wrapper structure for the vectors needed by Sequence grid CUDA methods. //! The \b surplusses is a copy of the Sequence grid surpluses and is used in the linear algebra (stage 2) of the evaluations. //! The \b nodes and \b coeffs are the 1D nodes and coefficients, needed for the basis evaluations (stage 1), //! more specifically used in the caching stage of the evaluation call. //! The \b points is a transposed copy of the nodes in the MultiIndexSet and \b num_nodes is one more than the number of nodes in each dimension. //! The \b points and \b num_nodes are needed for the accumulate stage of the basis evaluations. template struct CudaSequenceData{ GpuVector surpluses, nodes, coeff; GpuVector num_nodes, points; void clearNodes(){ nodes.clear(); coeff.clear(); num_nodes.clear(); points.clear(); } }; //! \internal //! \brief Wrapper structure for the vectors needed by Fourier grid CUDA methods. //! The \b real and \b imag values correspond to the real and complex part of the Fourier coefficients. //! The \b points is a transposed copy of the nodes in the MultiIndexSet and \b num_nodes is the number of nodes in each dimension. template struct CudaFourierData{ GpuVector real, imag; GpuVector num_nodes, points; }; //! \internal //! \brief Wrapper structure for the vectors needed by Local Polynomial grid CUDA methods. //! The \b surpluses are the hierarchical surpluses and used in the linear algebra (stage 2) of the evaluations. //! The \b nodes and \b support describe the basis functions, negative support is used to distinguish //! between local and global support and different order of the first few basis functions. //! The \b hpntr, \b hindx, and \b hroots, describe the hierarchy and are used in the sparse matrix algorithm. template struct CudaLocalPolynomialData{ GpuVector surpluses, nodes, support; GpuVector hpntr, hindx, hroots; void clearHierarchy(){ hpntr.clear(); hindx.clear(); hroots.clear(); } void clearBasisHierarchy(){ nodes.clear(); support.clear(); clearHierarchy(); } }; //! \internal //! \brief Wrapper structure for the vectors needed by Wavelet grid CUDA methods. //! The \b coefficients are the hierarchical coefficients and used in the linear algebra (stage 2) of the evaluations. template struct CudaWaveletData{ GpuVector coefficients, nodes, support; void clearNodes(){ nodes.clear(); support.clear(); } }; #endif // __TASMANIAN_DOXYGEN_SKIP } #endif TASMANIAN-8.1/SparseGrids/tsgDConstructGridGlobal.cpp000066400000000000000000000227531470551176200224050ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_DYNAMIC_CONST_GLOBAL_CPP #define __TASMANIAN_SPARSE_GRID_DYNAMIC_CONST_GLOBAL_CPP #include "tsgDConstructGridGlobal.hpp" namespace TasGrid{ template void DynamicConstructorDataGlobal::write(std::ostream &os) const{ if (use_ascii == mode_ascii){ os << std::scientific; os.precision(17); } auto tensor_refs = makeReverseReferenceVector(tensors); IO::writeNumbers(os, static_cast(tensor_refs.size())); for(auto d : tensor_refs){ IO::writeNumbers(os, d->weight); IO::writeVector(d->tensor, os); } writeNodeDataList(data, os); } template void DynamicConstructorDataGlobal::write(std::ostream &) const; // instantiate for faster build template void DynamicConstructorDataGlobal::write(std::ostream &) const; int DynamicConstructorDataGlobal::getMaxTensor() const{ int max_tensor = 0; for(auto const &t : tensors) max_tensor = std::max(max_tensor, *std::max_element(t.tensor.begin(), t.tensor.end())); return max_tensor; } void DynamicConstructorDataGlobal::reloadPoints(std::function getNumPoints){ for(auto &t : tensors){ MultiIndexSet dummy_set(num_dimensions, std::vector(t.tensor)); t.points = MultiIndexManipulations::generateNestedPoints(dummy_set, getNumPoints); t.loaded = std::vector((size_t) t.points.getNumIndexes(), false); } for(auto const &p : data){ // rebuild the loaded vectors for(auto &t : tensors){ int i = t.points.getSlot(p.point); if (i != -1) t.loaded[i] = true; } } } void DynamicConstructorDataGlobal::clearTesnors(){ for(auto t = tensors.begin(), p = tensors.before_begin(); t != tensors.end(); t++){ if (t->weight >= 0.0){ tensors.erase_after(p); t = p; }else{ p++; } // at each step, p starts before t, regardless if t is erased, p ends up equal to t, then t++ } } MultiIndexSet DynamicConstructorDataGlobal::getInitialTensors() const{ Data2D tens(num_dimensions, 0); for(auto const &t : tensors){ if (t.weight < 0.0) tens.appendStrip(t.tensor); } return MultiIndexSet(tens); } void DynamicConstructorDataGlobal::addTensor(const int *tensor, std::function getNumPoints, double weight){ tensors.emplace_front(TensorData{ weight, std::vector(tensor, tensor + num_dimensions), MultiIndexManipulations::generateNestedPoints(MultiIndexSet(num_dimensions, std::vector(tensor, tensor + num_dimensions)), getNumPoints), std::vector(), }); tensors.front().loaded = std::vector((size_t) tensors.front().points.getNumIndexes(), false); for(auto const &p : data){ int slot = tensors.front().points.getSlot(p.point); if (slot != -1) tensors.front().loaded[slot] = true; } if (std::all_of(tensors.front().loaded.begin(), tensors.front().loaded.end(), [](bool b)->bool{ return b; })){ tensors.front().loaded.clear(); } } MultiIndexSet DynamicConstructorDataGlobal::getNodesIndexes(){ std::vector inodes; auto get_weight = [](const TensorData &tensor)->double{ if (tensor.weight <= 0.0) return tensor.weight; if (tensor.loaded.empty()) return 0.0; // should not be happening, should have ejected int num_loaded = (int) std::count_if(tensor.loaded.begin(), tensor.loaded.end(), [](bool p)->bool{ return p; }); return tensor.weight * ((double(tensor.loaded.size()) - double(num_loaded)) / double(tensor.loaded.size())); }; tensors.sort([&](const TensorData &a, const TensorData &b)->bool{ return (get_weight(a) < get_weight(b)); }); for(auto const &t : tensors){ if (!t.loaded.empty()){ for(int i=0; i &point, const std::vector &value){ data.emplace_front(NodeData{point, value}); for(auto &t : tensors){ int slot = t.points.getSlot(point); if (slot != -1){ t.loaded[slot] = true; if (std::all_of(t.loaded.begin(), t.loaded.end(), [](bool a)-> bool{ return a; })){ // if all entries are true t.loaded = std::vector(); return AddPointResult::tensor_complete; // all points associated with this tensor have been loaded, signal to call ejectCompleteTensor() }else{ return AddPointResult::tensor_incomplete; // point added to the tensor, but the tensor is not complete yet } } } // could not find a tensor that contains this node, must add a new tensor return AddPointResult::tensor_missing; } void DynamicConstructorDataGlobal::ejectCompleteTensor(MultiIndexSet const ¤t_tensors, MultiIndexSet &new_tensors, MultiIndexSet &new_points, StorageSet &vals){ new_points = MultiIndexSet(); // reset tensors vals = StorageSet(); Data2D candidate_tensors(num_dimensions, 0); // get a list of completed tensors for(auto &t : tensors) if (t.loaded.empty()) candidate_tensors.appendStrip(t.tensor); // get the completed tensors that can be added to current_tensors while still preserving lower-completion new_tensors = MultiIndexManipulations::getLargestCompletion(current_tensors, MultiIndexSet(candidate_tensors)); if (new_tensors.empty()) return; vals.resize((int) num_outputs, 0); auto p = tensors.before_begin(), t = tensors.begin(); while(t != tensors.end()){ if (new_tensors.missing(t->tensor)){ // if not using this tensor, advance to the next t++; p++; }else{ // if using the tensor int num_searching = t->points.getNumIndexes(); Data2D wvals(num_outputs, num_searching); // find all the values of the points int found = 0; auto d = data.before_begin(); auto v = data.begin(); while(found < num_searching){ // until all are found int slot = t->points.getSlot(v->point); if (slot == -1){ // this is not a point that we are looking for d++; v++; }else{ // point found, copy the value and extract it from the list std::copy_n(v->value.begin(), num_outputs, wvals.getStrip(slot)); data.erase_after(d); v = d; v++; found++; } } vals.addValues(new_points, t->points, wvals.getStrip(0)); new_points += t->points; tensors.erase_after(p); t = p; t++; } } } } #endif TASMANIAN-8.1/SparseGrids/tsgDConstructGridGlobal.hpp000066400000000000000000000373231470551176200224110ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_DYNAMIC_CONST_GLOBAL_HPP #define __TASMANIAN_SPARSE_GRID_DYNAMIC_CONST_GLOBAL_HPP #include #include "tsgIndexManipulator.hpp" /*! * \internal * \file tsgDConstructGridGlobal.hpp * \brief Class and data types used for dynamic construction of Global grids. * \author Miroslav Stoyanov * \ingroup TasmanianRefinement * * Defines the storage class and struct types used for * construction of Global grids. The class is more complex than other * examples because rules with growth of more than one point need * to collect several samples before the grid can be extended with another * tensor. * \endinternal */ /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianRefinement Refinement related classes, structures, and methods * * \par Adaptive Refinement * The most efficient sparse grids approximation strategies are adaptive, * i.e., the grid is constructed to best capture the behavior of the specific * target model. Adapting a grid requires analysis of the existing loaded * model values followed by a decision on how to best expand the grid. * Sometimes the complexity of the refinement algorithms requires additional * data storage and methods implemented outside of the main grid classes. * \endinternal */ namespace TasGrid{ /*! * \internal * \ingroup TasmanianRefinement * \brief Holds the pair of point index and model value, the struct is used in a \b std::forward_list. * * Dynamic construction allows the data for the points to be given as input in any arbitrary order. * However, points cannot be added to any grid unless some conditions are satisfied, * e.g., the resulting set must be connected or lower complete. * The nodes that cannot be included yet are stored into a \b std::forward_list of \b NodeData structs, * the point is kept in a multi-index integer format and the value into a single vector. * \endinternal */ struct NodeData{ //! \brief The multi-index of the point. std::vector point; //! \brief The values of the model outputs at the point. std::vector value; }; /*! * \internal * \ingroup TasmanianRefinement * \brief Holds the description of a single tensor candidate for inclusion into the grid. * * Some grid, e.g., Global Grids, cannot include a single point at a time, but only enough data to form a tensor. * The candidate tensors are stored in a \b \b std::forward_list of \b TensorData until all the points * associated with the tensor are provided. * \endinternal */ struct TensorData{ //! \brief The weight indicates the relative importance of the tensor. double weight; //! \brief Multi-index of the tensor. std::vector tensor; //! \brief The points associated with the surplus operator, the tensor can be included only when all points are available. MultiIndexSet points; //! \brief For each point \b false if the model data is not yet available for the point, true otherwise. std::vector loaded; }; /*! * \internal * \ingroup TasmanianRefinement * \brief Takes a list and creates a vector of references in reversed order, needed for I/O so that read can be followed by push_front. * \endinternal */ template std::vector makeReverseReferenceVector(const std::forward_list &list){ size_t num_entries = (size_t) std::distance(list.begin(), list.end()); std::vector refs(num_entries); auto p = list.begin(); auto r = refs.rbegin(); while(p != list.end()) *r++ = &*p++; return refs; } /*! * \internal * \ingroup TasmanianRefinement * \brief Writes a NodeData std::forward_list to a file using either binary or ascii format. * \endinternal */ template void writeNodeDataList(const std::forward_list &data, std::ostream &os){ if (use_ascii == mode_ascii){ os << std::scientific; os.precision(17); } auto data_refs = makeReverseReferenceVector(data); IO::writeNumbers(os, static_cast(data_refs.size())); for(auto d : data_refs){ IO::writeVector(d->point, os); IO::writeVector(d->value, os); } } /*! * \internal * \ingroup TasmanianRefinement * \brief Reads a NodeData std::forward_list from a file using either binary or ascii format. * \endinternal */ template std::forward_list readNodeDataList(std::istream &is, size_t num_dimensions, size_t num_outputs){ std::forward_list data; int num_nodes = IO::readNumber(is); for(int i=0; i(is, num_dimensions), // point IO::readVector(is, num_outputs) // value }); } return data; } /*! * \internal * \ingroup TasmanianRefinement * \brief Reads a TensorData std::forward_list from a file using either binary or ascii format. * * \endinternal */ template std::forward_list readTensorDataList(std::istream &is, size_t num_dimensions){ std::forward_list tensors; int num_entries = IO::readNumber(is); for(int i=0; i(is), // weight IO::readVector(is, num_dimensions), // tensor MultiIndexSet(), // points, will be set later std::vector() // loaded, will be set later }); } return tensors; } /*! * \internal * \ingroup TasmanianRefinement * \brief Using MultiIndexManipulations::indexesToNodes() convert the \b node_list to actual points according to the rule. * * \endinternal */ template std::vector listToNodes(std::forward_list const &node_list, size_t num_dimensions, RuleLike const &rule){ std::vector result(Utils::size_mult(std::distance(node_list.begin(), node_list.end()), num_dimensions)); auto ix = result.begin(); for(auto const &t : node_list) ix = MultiIndexManipulations::indexesToNodes(t.point, rule, ix); return result; } /*! * \internal * \ingroup TasmanianRefinement * \brief Using MultiIndexManipulations::indexesToNodes() convert the \b node_list to actual points according to the rule. * * \endinternal */ template std::vector listToLocalNodes(std::forward_list const &node_list, size_t num_dimensions, callable_method rule){ std::vector result(Utils::size_mult(std::distance(node_list.begin(), node_list.end()), num_dimensions)); auto ix = result.begin(); for(auto const &t : node_list) ix = std::transform(t.point.begin(), t.point.end(), ix, rule); return result; } /*! * \internal * \ingroup TasmanianRefinement * \brief Helper class that stores data from dynamic construction of a Global grid. * * The class stores candidate tensors with corresponding weights * as well as the model data provided by the user. * When enough data has been computed to complete a tensor, * the tensor can be ejected with the points and model data returned in a format * that is easy to incorporate within the data structures of the \b GridGlobal class. */ class DynamicConstructorDataGlobal{ public: //! \brief Defines the result of adding a point to the list of know points with values. enum class AddPointResult { //! \brief Indicates the point was added to an existing tensor but more points are needed before processing the tensor. tensor_incomplete, //! \brief Indicates the point was added to an existing tensor and the tensor is ready for processing. tensor_complete, //! \brief Indicates the point is associated with an unknown tensor. tensor_missing }; //! \brief Constructor, requires that the dimension and the number of model outputs is specified. DynamicConstructorDataGlobal(size_t cnum_dimensions, size_t cnum_outputs) : num_dimensions(cnum_dimensions), num_outputs(cnum_outputs){} //! \brief Read constructor. template DynamicConstructorDataGlobal(std::istream &is, size_t cnum_dimensions, size_t cnum_outputs, iomode) : num_dimensions(cnum_dimensions), num_outputs(cnum_outputs), tensors(readTensorDataList(is, num_dimensions)), data(readNodeDataList(is, num_dimensions, num_outputs)) {} //! \brief Default destructor, release all used memory and erase all stored data. ~DynamicConstructorDataGlobal() = default; //! \brief Write the data to a stream using ascii or binary format. template void write(std::ostream &os) const; //! \brief Restrict data between \b ibegin and \b iend entries. void restrictData(int ibegin, int iend){ for(auto &d : data) d.value = std::vector(d.value.begin() + ibegin, d.value.begin() + iend); } //! \brief Returns the maximum index of any of the stored tensors. int getMaxTensor() const; //! \brief Returns the maximum tensor weight. double getMaxTensorWeight() const{ double maxw = 0; for(auto it = tensors.begin(); it != tensors.end(); it++){ if (it->weight > maxw) maxw = it->weight; } return maxw; } //! \brief Called after read, reinitializes the points and loaded structures for the tensors. void reloadPoints(std::function getNumPoints); //! \brief Delete the tensors with non-negative weights, i.e., clear all but the tensors selected by the initial grid. void clearTesnors(); //! \brief Get a set of all tensors with negative weight, i.e., the tensors selected for the initial run. MultiIndexSet getInitialTensors() const; //! \brief Add a new tensor to the candidates, with the given \b weight and using \b getNumPoints() to define the associated nodes. void addTensor(const int *tensor, std::function getNumPoints, double weight); //! \brief Get the node indexes of the points associated with the candidate tensors, the order is the same as the tensors sorted by ascending weight. MultiIndexSet getNodesIndexes(); //! \brief Add a new data point with the index and the value, returns information about the tensor. AddPointResult addNewNode(const std::vector &point, const std::vector &value); // returns whether a tensor is complete //! \brief Returns a new set of tensors, points and values that can be added to the current tensors. void ejectCompleteTensor(MultiIndexSet const ¤t_tensors, MultiIndexSet &new_tensors, MultiIndexSet &new_points, StorageSet &vals); private: size_t num_dimensions, num_outputs; std::forward_list tensors; std::forward_list data; }; /*! * \internal * \brief Holds a std::forward_list of pairs of points indexes and values, and a MultiIndexSet of initial nodes. * \ingroup TasmanianRefinement * * Used for Sequence and Local Polynomial grids, where points can be added to the grid only when they form * a lower complete set (sequence) or a connected graph (local polynomial). * However, in order to facilitate parallelism, significantly large number of candidate points should be considered at any time. * A large initial grid will allow parallelism, but nodes may be computed in any arbitrary order * hence data has to be stored temporarily and wait until it can be incorporated into the grid. * \endinternal */ struct SimpleConstructData{ //! \brief Default empty constructor. SimpleConstructData() = default; //! \brief Read constructor, requires the number of dimensions and outputs. template SimpleConstructData(std::istream &is, int num_dimensions, int num_outputs, iomode) : initial_points(MultiIndexSet(is, iomode())), data(readNodeDataList(is, num_dimensions, num_outputs)) {} //! \brief Keeps track of the initial point set, so those can be computed first. MultiIndexSet initial_points; //! \brief A list of pair indicating point and model output values. std::forward_list data; //! \brief Save to a file in either ascii or binary format. template void write(std::ostream &os) const{ initial_points.write(os); writeNodeDataList(data, os); } //! \brief Restrict data between \b ibegin and \b iend entries. void restrictData(int ibegin, int iend){ for(auto &d : data) d.value = std::vector(d.value.begin() + ibegin, d.value.begin() + iend); } //! \brief Remove \b points from the \b data and return a vector of the values in the \b points order. std::vector extractValues(MultiIndexSet const &points){ size_t num_outputs = data.front().value.size(); int num_points = points.getNumIndexes(); Data2D result(num_outputs, num_points); auto p = data.before_begin(); auto d = data.begin(); while(d != data.end()){ int slot = points.getSlot(d->point); if (slot != -1){ // found a point std::copy_n(d->value.begin(), num_outputs, result.getStrip(slot)); data.erase_after(p); d = p; d++; }else{ p++; d++; } } return result.release(); } }; } #endif TASMANIAN-8.1/SparseGrids/tsgDpcppBasisEvaluations.hpp000066400000000000000000000507131470551176200226330ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_DPCPP_BASIS_EVALUATIONS_HPP #define __TASMANIAN_SPARSE_GRID_DPCPP_BASIS_EVALUATIONS_HPP #include "TasmanianConfig.hpp" #ifndef Tasmanian_ENABLE_DPCPP #error "Cannot use tsgDpcppBasisEvaluations.hpp without Tasmanian_ENABLE_DPCPP" #endif #define MKL_INT int #include #include "oneapi/mkl.hpp" namespace TasGrid{ template struct tsg_transformed_to_canonical_kernel{}; template // transformed and canonical types void tasgpu_transformed_to_canonical(sycl::queue *q, int dims, int num_x, int size_a, const C *gpu_trans_a, const C *gpu_trans_b, const T *gpu_x_transformed, T *gpu_x_canonical){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<1>{static_cast(dims * num_x), }, [=](sycl::id<1> threadId){ int i = threadId[0] % size_a; gpu_x_canonical[threadId[0]] = static_cast(gpu_x_transformed[threadId[0]] * gpu_trans_a[i] - gpu_trans_b[i]); }); }); q->wait(); } template struct tsg_m11_to_01_kernel{}; // convert (-1, 1) to (0, 1) template void tasgpu_m11_to_01(sycl::queue *q, int num_points, T *gpu_x){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<1>{static_cast(num_points), }, [=](sycl::id<1> threadId){ size_t i = threadId[0]; gpu_x[i] = ( gpu_x[i] + 1.0 ) / 2.0; }); }); q->wait(); } template struct tsg_seq_build_cache_kernel{}; template void tasgpu_dseq_build_cache(sycl::queue *q, int dims, int num_x, const T *gpuX, const T *nodes, const T *coeffs, const int *offsets, const int *num_nodes, T *result){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<1>{static_cast(num_x), }, [=](sycl::id<1> threadId){ int i = threadId[0]; for(int d=0; dwait(); } template struct tsg_seq_eval_sharedpoints_kernel{}; template void tasgpu_dseq_eval_sharedpoints(sycl::queue *q, int dims, int num_x, int num_points, const int *points, const int *offsets, const T *cache, T *result){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<2>{static_cast(num_points), static_cast(num_x)}, [=](sycl::id<2> threadId){ int id_p = threadId[0]; int id_x = threadId[1]; double v = cache[num_x * points[id_p] + id_x]; for(int j=1; jwait(); } template inline T linear_boundary_wavelet(T x){ if (fabs(x + 0.5) > 0.5) return 0.0; if (x <= -0.75){ return 0.75 * (7.0 * x + 6.0); }else if (x <= -0.5){ return -0.25 * (11.0 * x + 6.0); }else{ return 0.25 * x; } } template inline T linear_central_wavelet(T x){ if (fabs(x + 0.25) > 0.75) return 0.0; if (x <= -0.5){ return -0.5 * x - 0.5; }else if (x >= 0.0){ return 0.5 * x - 0.25; }else if (x <= -0.25){ return 4.0 * x + 1.75; }else{ return -4.0 * x - 0.25; } } template inline T tasgpu_devalpwpoly_feval(const double x, const double node, const double support){ // <- arrays are cached T v; if (rule == rule_localp){ if (order == 0){ v = (fabs(x - node) > support) ? 0.0 : 1.0; }else if (order == 1){ v = 1.0 - fabs(x - node) / support; if (support == -1.0) v = 1.0; if (v < 0.0) v = 0.0; }else if (order == 2){ v = x - node; v *= v; v = 1.0 - v / support; if (support == -1.0) v = 1.0; if (support == -2.0) v = -x; if (support == -3.0) v = x; if (v < 0.0) v = 0.0; } }else if (rule == rule_localp0){ if (order == 1){ v = 1.0 - fabs(x - node) / support; if (v < 0.0) v = 0.0; }else if (order == 2){ v = x - node; v *= v; v = 1.0 - v / support; if (v < 0.0) v = 0.0; } }else if (rule == rule_localpb){ if (order == 1){ v = 1.0 - fabs(x - node) / support; if (v < 0.0) v = 0.0; }else if (order == 2){ if (support == -2.0){ v = 1.0 + fabs(x - node) / support; }else{ v = x - node; v *= v; v = 1.0 - v / support; if (v < 0.0) v = 0.0; } } }else if (rule == rule_semilocalp){ if (order == 2){ v = x - node; v *= v; v = 1.0 - v / support; if (v < 0.0) v = 0.0; if (support == -1.0) v = 1.0; if (support == -4.0) v = 0.5 * x * (x - 1.0); if (support == -5.0) v = 0.5 * x * (x + 1.0); } }else{ // wavelet, node = scale, support = shift and encodes the type of wavelet // sync with RuleWavelet::getShiftScale() if (support == -1.0){ // level 0, using basic hat-functions v = 1.0 - fabs(x - node); if (v < 0.0) v = 0.0; }else if (support == -2.0){ // left boundary v = linear_boundary_wavelet(node * (x + 1.0) - 1.0); }else if (support == -3.0){ // right boundary v = linear_boundary_wavelet(node * (1.0 - x) - 1.); }else{ v = linear_central_wavelet(node * (x + 1.0) - 1.0 - support); } } return v; } template struct tasgpu_devalpwpoly_kernel{}; template // rule: localp0, localp, semilocalp void tasgpu_devalpwpoly(sycl::queue *q, int dims, int num_x, int num_points, const T *gpu_x, const T *gpu_nodes, const T *gpu_support, T *gpu_y){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<2>{static_cast(num_points), static_cast(num_x)}, [=](sycl::id<2> threadId){ int id_p = threadId[0]; int id_x = threadId[1]; T v = 1.0; for(int j=0; j(gpu_x[id_x * dims + j], gpu_nodes[id_p * dims + j], gpu_support[id_p * dims + j]); gpu_y[id_x * num_points + id_p] = v; }); }); q->wait(); } template inline T tasgpu_devalpwpoly_basis_multid(int dims, int i, int ip, const T *x, const T *nodes, const T *support){ T p = 1.0; for(int j=0; j(this_x, this_node, this_supp); } return p; } template inline T tasgpu_devalpwpoly_support_pwc_multid(int dims, int i, int ip, const T *x, const T *nodes, const T *support){ T p = 1.0; for(int j=0; j 2.0 * support[ip * dims + j]) ? 0.0 : 1.0); } return p; } template struct tasgpu_devalpwpoly_sparse_kernel{}; template void tasgpu_devalpwpoly_sparse(sycl::queue *q, int dims, int num_x, const T *x, const T *nodes, const T *support, const int *hpntr, const int *hindx, int num_roots, const int *roots, int *spntr, int *sindx, T *svals){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<1>{static_cast(num_x),}, [=](sycl::id<1> threadId){ int mcount[TOPLEVEL]; int mstop[TOPLEVEL]; int c = 0; int i = threadId[0]; if (fill) c = spntr[i]; for(int r=0; r 0) ? tasgpu_devalpwpoly_basis_multid(dims, i, ip, x, nodes, support) : tasgpu_devalpwpoly_support_pwc_multid(dims, i, ip, x, nodes, support); if (p != 0.0){ if (fill){ sindx[c] = ip; if (order == 0){ p = tasgpu_devalpwpoly_basis_multid(dims, i, ip, x, nodes, support);; } svals[c] = p; } c++; int current = 0; mstop[0] = hpntr[ip + 1]; mcount[0] = hpntr[ip]; while(mcount[0] < mstop[0]){ if (mcount[current] < mstop[current]){ ip = hindx[mcount[current]]; if (order > 0){ p = tasgpu_devalpwpoly_basis_multid(dims, i, ip, x, nodes, support); }else{ p = tasgpu_devalpwpoly_support_pwc_multid(dims, i, ip, x, nodes, support); } if (p != 0.0){ if (fill){ sindx[c] = ip; if (order == 0){ p = tasgpu_devalpwpoly_basis_multid(dims, i, ip, x, nodes, support);; } svals[c] = p; } c++; current++; mstop[current] = hpntr[ip + 1]; mcount[current] = hpntr[ip]; }else{ mcount[current]++; } }else{ current--; mcount[current]++; } } } } if (not fill) spntr[i+1] = c; }); }); q->wait(); } template struct tasgpu_dfor_build_cache_kernel{}; template void tasgpu_dfor_build_cache(sycl::queue *q, int dims, int num_x, const T *gpuX, const int *offsets, const int *num_nodes, T *result){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<1>{static_cast(num_x),}, [=](sycl::id<1> threadId){ int i = threadId[0]; for(int d=0; dwait(); } template struct tasgpu_dfor_eval_sharedpoints_kernel{}; template void tasgpu_dfor_eval_sharedpoints(sycl::queue *q, int dims, int num_x, int num_points, const int *points, const int *offsets, const T *cache, T *wreal, T *wimag){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<2>{static_cast(num_points), static_cast(num_x)}, [=](sycl::id<2> threadId){ int id_p = threadId[0]; int id_x = threadId[1]; T vreal = cache[2 * num_x * points[id_p] + id_x]; T vimag = cache[2 * num_x * points[id_p] + num_x + id_x]; for(int j=1; jwait(); } template struct tsg_glo_build_cache_kernel{}; template void tasgpu_dglo_build_cache(sycl::queue *q, int num_dims, int num_x, int cache_lda, T const *gpu_x, T const *nodes, T const *coeff, int const *nodes_per_level, int const *offset_per_level, int const *dim_offsets, int const *map_dimension, int const *map_level, T *cache){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<2>{static_cast(cache_lda), static_cast(num_x)}, [=](sycl::id<2> threadID){ int blkid = threadID[0]; int idx = threadID[1]; int dim = map_dimension[blkid]; // get the dim for this thread block int lvl = map_level[blkid]; // get the level for the thread block int num_nodes = nodes_per_level[lvl]; int opl = offset_per_level[lvl]; T x = gpu_x[idx * num_dims + dim]; // get the local x int cache_offset = (dim_offsets[dim] + opl) * num_x; T c = 1.0; cache[cache_offset + idx] = c; for(int j=0; j0; j--){ c *= (nested) ? (x - nodes[j]) : (x - nodes[opl + j]); cache[cache_offset + idx] *= c * coeff[opl + j - 1]; cache_offset -= num_x; } }); }); q->wait(); } template struct tsg_glo_eval_zero_kernel{}; template void tasgpu_dglo_eval_zero(sycl::queue *q, size_t size, T *result){ q->submit([&](sycl::handler& h) { h.parallel_for>(sycl::range<1>{size,}, [=](sycl::id<1> i){ result[i[0]] = static_cast(0.0); }); }); q->wait(); } template struct tsg_glo_eval_sharedpoints_kernel{}; template void tasgpu_dglo_eval_sharedpoints(sycl::queue *q, int num_dims, int num_x, int loop_lda, int result_lda, T const *cache, T const *tweights, int const *offset_per_level, int const *dim_offsets, int const *active_tensors, int const *active_num_points, int const *map_tensor, int const *map_index, int const *map_reference, T *result){ q->submit([&](sycl::handler& h){ h.parallel_for>(sycl::range<1>{static_cast(1),}, [=](sycl::id<1>){ // this can be called in parallel_for over both bklid and idx (using loop_lda and num_x) // running this in parallel requires the atomicAdd() for(int blkid = 0; blkid < loop_lda; blkid++){ int tensor = map_tensor[blkid]; // get the tensor for this thread block int ref = map_reference[blkid]; int toff = tensor * num_dims; for(int idx = 0; idx < num_x; idx++){ int index = map_index[blkid]; // get the index for the thread block T w = 1.0; for(int j=num_dims-1; j>=0; j--){ w *= cache[(dim_offsets[j] + offset_per_level[active_tensors[toff + j]] + index % active_num_points[toff + j]) * num_x + idx]; index /= active_num_points[toff + j]; } //sycl::atomic_fetch_add(result[idx * result_lda + ref], tweights[tensor] * w); result[idx * result_lda + ref] += tweights[tensor] * w; } } }); }); q->wait(); } } #endif TASMANIAN-8.1/SparseGrids/tsgDpcppKernels.cpp000066400000000000000000000444141470551176200207560ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_HIP_KERNELS_HIP #define __TASMANIAN_SPARSE_GRID_HIP_KERNELS_HIP #include "tsgAcceleratedDataStructures.hpp" #include "tsgDpcppBasisEvaluations.hpp" #include "tsgDpcppWrappers.hpp" #define _MAX_THREADS 1024 namespace TasGrid{ template void TasGpu::dtrans2can(AccelerationContext const *acc, bool use01, int dims, int num_x, int pad_size, double const *gpu_trans_a, double const *gpu_trans_b, T const *gpu_x_transformed, T *gpu_x_canonical){ sycl::queue *q = getSyclQueue(acc); tasgpu_transformed_to_canonical(q, dims, num_x, pad_size, gpu_trans_a, gpu_trans_b, gpu_x_transformed, gpu_x_canonical); if (use01) tasgpu_m11_to_01(q, dims * num_x, gpu_x_canonical); } template void TasGpu::dtrans2can(AccelerationContext const*, bool, int, int, int, double const*, double const*, double const*, double*); template void TasGpu::dtrans2can(AccelerationContext const*, bool, int, int, int, double const*, double const*, float const*, float*); // local polynomial basis functions, DENSE algorithm template void TasGpu::devalpwpoly(AccelerationContext const *acc, int order, TypeOneDRule rule, int dims, int num_x, int num_points, const T *gpu_x, const T *gpu_nodes, const T *gpu_support, T *gpu_y){ sycl::queue *q = getSyclQueue(acc); // order == 1 is considered "default" so that the compiler doesn't complain about missing default statement // semilocalp cannot have order less than 2, only rule_localp can have order 0 (this gets overwrittein in makeLocalPolynomialGrid()) if (rule == rule_localp){ switch(order){ case 0: tasgpu_devalpwpoly(q, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; case 2: tasgpu_devalpwpoly(q, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; default: tasgpu_devalpwpoly(q, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } }else if (rule == rule_localp0){ switch(order){ case 2: tasgpu_devalpwpoly(q, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; default: tasgpu_devalpwpoly(q, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } }else if (rule == rule_localpb){ switch(order){ case 2: tasgpu_devalpwpoly(q, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; default: tasgpu_devalpwpoly(q, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } }else if (rule == rule_semilocalp){ tasgpu_devalpwpoly(q, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); }else{ // rule == wavelet tasgpu_devalpwpoly(q, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } } template void TasGpu::devalpwpoly(AccelerationContext const*, int, TypeOneDRule, int, int, int, const double*, const double*, const double*, double*); template void TasGpu::devalpwpoly(AccelerationContext const*, int, TypeOneDRule, int, int, int, const float*, const float*, const float*, float*); // there is a switch statement that realizes templates for each combination of rule/order // make one function that covers that switch, the rest is passed from devalpwpoly_sparse template inline void devalpwpoly_sparse_realize_rule_order(AccelerationContext const *acc, int order, TypeOneDRule rule, int dims, int num_x, const T *x, const T *nodes, const T *support, const int *hpntr, const int *hindx, int num_roots, const int *roots, int *spntr, int *sindx, T *svals){ sycl::queue *q = getSyclQueue(acc); if (rule == rule_localp){ switch(order){ case 0: tasgpu_devalpwpoly_sparse (q, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; case 2: tasgpu_devalpwpoly_sparse (q, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; default: tasgpu_devalpwpoly_sparse (q, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } }else if (rule == rule_localp0){ switch(order){ case 2: tasgpu_devalpwpoly_sparse (q, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; default: tasgpu_devalpwpoly_sparse (q, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } }else if (rule == rule_localpb){ switch(order){ case 2: tasgpu_devalpwpoly_sparse (q, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; default: tasgpu_devalpwpoly_sparse (q, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } }else{ // rule == rule_semilocalp tasgpu_devalpwpoly_sparse (q, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } } // local polynomial basis functions, SPARSE algorithm (2 passes, one pass to compue the non-zeros and one pass to evaluate) template void TasGpu::devalpwpoly_sparse(AccelerationContext const *acc, int order, TypeOneDRule rule, int dims, int num_x, const T *gpu_x, const GpuVector &gpu_nodes, const GpuVector &gpu_support, const GpuVector &gpu_hpntr, const GpuVector &gpu_hindx, const GpuVector &gpu_hroots, GpuVector &gpu_spntr, GpuVector &gpu_sindx, GpuVector &gpu_svals){ gpu_spntr.resize(acc, num_x + 1); // call with fill == false to count the non-zeros per row of the matrix devalpwpoly_sparse_realize_rule_order (acc, order, rule, dims, num_x, gpu_x, gpu_nodes.data(), gpu_support.data(), gpu_hpntr.data(), gpu_hindx.data(), (int) gpu_hroots.size(), gpu_hroots.data(), gpu_spntr.data(), 0, 0); std::vector cpu_spntr; gpu_spntr.unload(acc, cpu_spntr); cpu_spntr[0] = 0; int nz = 0; for(auto &i : cpu_spntr){ i += nz; nz = i; } gpu_spntr.load(acc, cpu_spntr); gpu_sindx.resize(acc, nz); gpu_svals.resize(acc, nz); // call with fill == true to load the non-zeros devalpwpoly_sparse_realize_rule_order (acc, order, rule, dims, num_x, gpu_x, gpu_nodes.data(), gpu_support.data(), gpu_hpntr.data(), gpu_hindx.data(), (int) gpu_hroots.size(), gpu_hroots.data(), gpu_spntr.data(), gpu_sindx.data(), gpu_svals.data()); } template void TasGpu::devalpwpoly_sparse(AccelerationContext const*, int, TypeOneDRule, int, int, const double*, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, GpuVector&, GpuVector&, GpuVector&); template void TasGpu::devalpwpoly_sparse(AccelerationContext const*, int, TypeOneDRule, int, int, const float*, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, GpuVector&, GpuVector&, GpuVector&); // Sequence Grid basis evaluations template void TasGpu::devalseq(AccelerationContext const *acc, int dims, int num_x, const std::vector &max_levels, const T *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, T *gpu_result){ sycl::queue *q = getSyclQueue(acc); std::vector offsets(dims); offsets[0] = 0; for(int d=1; d gpu_offsets(acc, offsets); GpuVector cache1D(acc, num_total); tasgpu_dseq_build_cache (q, dims, num_x, gpu_x, nodes.data(), coeffs.data(), gpu_offsets.data(), num_nodes.data(), cache1D.data()); tasgpu_dseq_eval_sharedpoints (q, dims, num_x, (int) points.size() / dims, points.data(), gpu_offsets.data(), cache1D.data(), gpu_result); } template void TasGpu::devalseq(AccelerationContext const*, int dims, int num_x, const std::vector &max_levels, const double *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, double *gpu_result); template void TasGpu::devalseq(AccelerationContext const*, int dims, int num_x, const std::vector &max_levels, const float *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, float *gpu_result); // Fourier Grid basis evaluations template void TasGpu::devalfor(AccelerationContext const *acc, int dims, int num_x, const std::vector &max_levels, const T *gpu_x, const GpuVector &num_nodes, const GpuVector &points, T *gpu_wreal, typename GpuVector::value_type *gpu_wimag){ sycl::queue *q = getSyclQueue(acc); std::vector max_nodes(dims); for(int j=0; j offsets(dims); offsets[0] = 0; for(int d=1; d gpu_offsets(acc, offsets); GpuVector cache1D(acc, num_total); tasgpu_dfor_build_cache(q, dims, num_x, gpu_x, gpu_offsets.data(), num_nodes.data(), cache1D.data()); if (gpu_wimag == 0){ tasgpu_dfor_eval_sharedpoints (q, dims, num_x, (int) points.size() / dims, points.data(), gpu_offsets.data(), cache1D.data(), gpu_wreal, 0); }else{ tasgpu_dfor_eval_sharedpoints (q, dims, num_x, (int) points.size() / dims, points.data(), gpu_offsets.data(), cache1D.data(), gpu_wreal, gpu_wimag); } } template void TasGpu::devalfor(AccelerationContext const*, int, int, const std::vector&, const double*, const GpuVector&, const GpuVector&, double*, double*); template void TasGpu::devalfor(AccelerationContext const*, int, int, const std::vector&, const float*, const GpuVector&, const GpuVector&, float*, float*); template void TasGpu::devalglo(AccelerationContext const *acc, bool is_nested, bool is_clenshawcurtis0, int dims, int num_x, int num_p, int num_basis, T const *gpu_x, GpuVector const &nodes, GpuVector const &coeff, GpuVector const &tensor_weights, GpuVector const &nodes_per_level, GpuVector const &offset_per_level, GpuVector const &map_dimension, GpuVector const &map_level, GpuVector const &active_tensors, GpuVector const &active_num_points, GpuVector const &dim_offsets, GpuVector const &map_tensor, GpuVector const &map_index, GpuVector const &map_reference, T *gpu_result){ GpuVector cache(acc, num_x, num_basis); sycl::queue *q = getSyclQueue(acc); if (is_nested){ if (is_clenshawcurtis0){ tasgpu_dglo_build_cache (q, dims, num_x, (int) map_dimension.size(), gpu_x, nodes.data(), coeff.data(), nodes_per_level.data(), offset_per_level.data(), dim_offsets.data(), map_dimension.data(), map_level.data(), cache.data()); }else{ tasgpu_dglo_build_cache (q, dims, num_x, (int) map_dimension.size(), gpu_x, nodes.data(), coeff.data(), nodes_per_level.data(), offset_per_level.data(), dim_offsets.data(), map_dimension.data(), map_level.data(), cache.data()); } }else{ tasgpu_dglo_build_cache (q, dims, num_x, (int) map_dimension.size(), gpu_x, nodes.data(), coeff.data(), nodes_per_level.data(), offset_per_level.data(), dim_offsets.data(), map_dimension.data(), map_level.data(), cache.data()); } tasgpu_dglo_eval_zero(q, Utils::size_mult(num_x, num_p), gpu_result); tasgpu_dglo_eval_sharedpoints (q, dims, num_x, (int) map_tensor.size(), num_p, cache.data(), tensor_weights.data(), offset_per_level.data(), dim_offsets.data(), active_tensors.data(), active_num_points.data(), map_tensor.data(), map_index.data(), map_reference.data(), gpu_result); } template void TasGpu::devalglo(AccelerationContext const*, bool, bool, int, int, int, int, double const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, double*); template void TasGpu::devalglo(AccelerationContext const*, bool, bool, int, int, int, int, float const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, float*); void TasGpu::fillDataGPU(AccelerationContext const *acc, double value, long long n, long long stride, double data[]){ sycl::queue *q = getSyclQueue(acc); if (stride == 1){ q->submit([&](sycl::handler& h) { h.parallel_for(sycl::range<1>{static_cast(n),}, [=](sycl::id<1> threadId){ data[threadId[0]] = value; }); }); q->wait(); }else{ q->submit([&](sycl::handler& h) { h.parallel_for(sycl::range<1>{static_cast(n),}, [=](sycl::id<1> threadId){ data[threadId[0] * stride] = value; }); }); q->wait(); } } } #endif TASMANIAN-8.1/SparseGrids/tsgEnumerates.hpp000066400000000000000000001011441470551176200204730ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_ENUMERATES_HPP #define __TASMANIAN_SPARSE_GRID_ENUMERATES_HPP // system headers used in many/many places #ifdef _MSC_VER // without this MSVC++ does not accepts keywords such as "not" and "or" #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "TasmanianConfig.hpp" // contains build options passed down from CMake #include "tsgUtils.hpp" // contains small utilities /*! * \internal * \file tsgEnumerates.hpp * \brief Omnipresent enumerate types. * \author Miroslav Stoyanov * \ingroup TasmanianEnumerates * * Contains the enumerate types that are used throughout Tasmanian. * This header is included directly or transitively in every other * file of the project including \b TasmanianSparseGrids.hpp * \endinternal */ /*! * \ingroup TasmanianSG * \addtogroup SGEnumerates Enumerated types * * \par Enumerated types * Enumerations are used as input to many Tasmanian functions * in both internal and external API. */ namespace TasGrid{ /*! * \internal * \ingroup TasmanianEnumerates * \brief Defines the integer used by the LAPACK methods, usually int but DPC++ uses int64_t. * * \endinternal */ #ifdef Tasmanian_ENABLE_DPCPP using int_gpu_lapack = std::int64_t; #else using int_gpu_lapack = int; #endif //! \internal //! \brief Describes the relation between two multi-indexes when compared during sorting. //! \ingroup SGEnumerates //! The standard C++11 algorithms std::merge and std::binary_search use bools as return //! types when comparing entries, thus in the case of many repeated entries, two //! comparisons have to be performed. Repeated entries are encountered in many sparse //! grids algorithms, especially when dealing with nested one dimensional rules. //! Thus, for performance reasons, Tasmanian implements merging and searching //! methods that compare multi-indexes and produce three outcomes in a single comparison. //! //! Specifically, see \b SetManipulations::push_merge_map() and \b MultiIndexSet::getSlot() //! and \b MultiIndexSet::addSortedInsexes() enum TypeIndexRelation{ // internal for IndexSets, unambiguous set comparison //! \brief Indicates that the first multi-index in the call to compare comes before the second. type_abeforeb, //! \brief Indicates that the second multi-index in the call to compare after the second. type_bbeforea, //! \brief Indicates that the two multi-indexes are the same. type_asameb }; /*! * \brief Used by Global Sequence and Fourier grids, indicates the selection criteria. * \ingroup SGEnumerates * * \par Approximation Error * The approximation error when interpolating or integrating a target model with * a \b Global sparse grid, * is bound by a constant multiplied by the best approximation of the model in the * set of polynomial exactness. The exactness set consists of all polynomials that * can be \a captured exactly (approximated to round-off error) by the sparse grid. * The constant is the * norm of the sparse grid operator (a.k.a., the Lebesgue constant) * and the exactness set is the range. * * \par * The operator norm depends primarily on the underlying one dimensional rule used * to construct the grid, and all rules implemented in Tasmanian have reasonable norms. * Of primary focus is the target model and constructing a grid with range suitable * for either integrating or interpolating the model. * * \par Categories * The types of \b Global grids fall into four categories: * - \b Level selection uses the order of the one dimensional rules as criteria * and pays no regard to the polynomial exactness. \b Level types are strongly influenced * by the growth of points in the one dimensional rule and are seldom optimal, * although such grid can be a good initial guess for an iterative refinement process. * - \b Total degree polynomial space is good for smooth models, i.e., analytic functions * with convergent Taylor series for every point in the domain. * - \b Curved polynomial space is essentially a \b Total degree space with an * added logarithmic correction term. The correction can account for rules with slightly * higher norm growth (e.g., R-Leja rules) or for models with heavily constrained * region of analytic extension, i.e., slightly less smooth. * - \b Hyperbolic cross section space is suitable for models with more irregular behavior, e.g., * models with only a finite number of derivatives. * * \par * The four main types can be tuned for either interpolation or quadrature (integration); * the corresponding enumerate will have either \b i or \b q in the name. * In all cases, Tasmanian will construct the grid with minimum number of points * (or fewest basis functions), that will \a capture the corresponding polynomial space. * * \par Anisotropic Weights * All types can be combined with anisotropic weights that adjust the density * of the grid in different directions. Below, we denote the anisotropic weights * with \f$ \xi_1, \xi_2, \cdots, \xi_d \f$ and \f$ \eta_1, \eta_2, \cdots, \eta_d \f$, * where \f$ d \f$ is the number of dimensions in the grid. Note that only curved * types use the \f$ \eta \f$ weights. * * \par * The \b TypeDepth also uses the \b depth parameter to define a cut-off point, the * \b depth is normalized by multiplying it by the smallest of the \f$ \xi \f$ weights. * In the formulas below, \b L stands for the normalized offset. * * Details regarding sparse grids construction and polynomial spaces can be found in\n * M. Stoyanov, C. G. Webster, * A Dynamically Adaptive Sparse Grid Method for Quasi-Optimal * Interpolation of Multidimensional Analytic Functions, arXiv:1508.01125.\n * also published in * Computers and Mathematics with Applications 71 (2016) 2449–2465. * * \par Full Tensor Types * Finally, in addition to the aforementioned types, Tasmanian includes the types for * dense tensor grids. Only in 2-dimensions Gauss quadrature rules with full tensors * are more efficient than a general sparse grid. Performing interpolation or * working with more than 2 dimensions, sparse grids will always result in better * approximation error per number of nodes, i.e., model evaluations; nevertheless, * dense tensor grids naturally fall in the framework and can be useful for testing * purposes. * * \par Fourier Grids * The Fourier grids are very similar to Global grids, with the exception that * polynomial powers are replaced by frequencies of trigonometric functions. * The different selection strategies can be used with frequency exactness in * place of polynomial power. * * The structure of the Fourier spaces, the convergence estimates, and * the refinement strategies are described in\n * Z. Morrow, M. Stoyanov, A Method for * Dimensionally Adaptive Sparse Trigonometric Interpolation of Periodic Functions, * arXiv:1908.10672. */ enum TypeDepth{ //! \brief Null type, should \b never be used for input, indicates an error of some sort. type_none, //! \brief Ignoring the polynomial space, use rules with index //! \f$ \left\{ (i_1, i_2, \cdots, i_d) : \sum_{k=1}^d \xi_k i_k \leq L \right\} \f$ type_level, //! \brief Ignoring the polynomial space, use rules with index \n //! \f$ \left\{ (i_1, i_2, \cdots, i_d) : \sum_{k=1}^d \xi_k i_k + \sum_{k=1}^d \eta_k \log(i_k + 1) \leq L \right\} \f$ type_curved, //! \brief Ignoring the polynomial space, use rules with index //! \f$ \left\{ (i_1, i_2, \cdots, i_d) : \prod_{k=1}^d (i_k + 1)^{\xi_k} \leq L \right\} \f$ type_hyperbolic, //! \brief Total degree polynomial space for interpolation, i.e., the span of \n //! \f$ \left\{ \prod_{k=1}^d x^{i_k} : \sum_{k=1}^d \xi_k i_k \leq L \right\} \f$ type_iptotal, //! \brief Total degree polynomial space for quadrature/integration. type_qptotal, //! \brief Curved polynomial space for interpolation, i.e., the span of \n //! \f$ \left\{ \prod_{k=1}^d x^{i_k} : \sum_{k=1}^d \xi_k i_k + \sum_{k=1}^d \eta_k \log(i_k + 1) \leq L \right\} \f$ type_ipcurved, //! \brief Curved polynomial space for quadrature/integration. type_qpcurved, //! \brief Hyperbolic cross section polynomial space for interpolation, i.e., the span of \n //! \f$ \left\{ \prod_{k=1}^d x^{i_k} : \prod_{k=1}^d (i_k + 1)^{\xi_k} \leq L \right\} \f$ type_iphyperbolic, //! \brief Hyperbolic cross section polynomial space for quadrature/integration. type_qphyperbolic, //! \brief Make a dense tensor grid with rules indexed by \f$ \xi_1, \xi_2, \cdots, \xi_d \f$ type_tensor, //! \brief Make a dense tensor grid with interpolation range that includes //! \f$ \left\{ \prod_{k=1}^d x^{i_k} : i_k \leq \xi_k \mbox{ for all } k \right\} \f$ type_iptensor, //! \brief Make a dense tensor grid with quadrature/integration range that includes //! \f$ \left\{ \prod_{k=1}^d x^{i_k} : i_k \leq \xi_k \mbox{ for all } k \right\} \f$ type_qptensor }; //! \brief Used to specify the one dimensional family of rules that induces the sparse grid. //! \ingroup SGEnumerates //! \par One Dimensional Rules //! A sparse grid is a superposition of tensors of one dimensional rules with varying precision //! in the different directions. In this context, a \b TypeOneDRule defines a family of one //! dimensional rules with corresponding abscissas (nodes), quadrature weights, and //! basis functions. //! //! \par Categories //! The rules fall into 5 categories, corresponding to the 5 main classes of grids. //! - \b Global using Lagrange polynomials for interpolation and (sometimes) specialized //! quadrature weights. //! - \b Sequence rules are a subset of the \b Global rules, \b Sequence rules are always //! nested and each level adds one node to the previous level. //! - \b Local \b Polynomial rules use uniformly spaced nodes and polynomial basis with //! localized support. //! - \b Wavelet and \b Fourier rules also use uniformly spaced nodes, but with //! wavelet and trigonometric basis functions. //! //! \par Special Quadrature //! All rules can be used to approximate integrals of the form \f$ \int_\Gamma f(x) \rho(x) dx \f$ //! where \f$ \Gamma \f$ is the (transformed) domain and \f$ f(x) \f$ is the model. //! The majority of rules assume that the weight is constant 1, but in some cases //! more exotic weights are used. Assume that constant weight 1 is used, unless otherwise //! specified. //! //! \par Domain Transformation //! Most rules are defined on a canonical interval [-1, 1], which can be transformed to an //! arbitrary [a, b] with \b TasmanianSparseGrid::setDomainTransform(), so long as \b a is less than \b b. //! Fourier grids use canonical [0, 1] and can be similarly transformed to [a, b]. Gauss-Laguerre rule //! is set to \f$ [0, \infty) \f$ transformed to \f$ [a, \infty) \f$ with scale parameter \b b (see below). //! Gauss-Hermite is set to \f$ (-\infty, \infty) \f$ with scale and shift parameters. enum TypeOneDRule{ //! \brief Null rule, should \b never be used as input (default rule for an empty grid). rule_none, //! \brief Classic nested rule using Chebyshev nodes with very low Lebesgue constant. rule_clenshawcurtis, //! \brief Same as \b rule_clenshawcurtis but with modified basis that assumes the model is zero at the boundary. rule_clenshawcurtis0, //! \brief Similar to \b rule_clenshawcurtis but with nodes strictly in the interior. rule_fejer2, //! \brief Using Chebyshev nodes with very low Lebesgue constant and slow node growth, but non-nested. rule_chebyshev, //! \brief Same as \b rule_chebyshev but using only odd levels, partially mitigates the non-nested issues. rule_chebyshevodd, //! \brief Classic \b sequence rule, moderate Lebesgue constant growth (empirical result only). rule_leja, //! \brief Same as \b rule_leja but using only odd levels, quadrature is more stable. rule_lejaodd, //! \brief Classic \b sequence rule based on complex analysis, moderate Lebesgue constant growth (theoretically proven). rule_rleja, //! \brief Using \b rule_rleja nodes but doubling the nodes every 2 levels, reduces the Lebesgue constant. rule_rlejadouble2, //! \brief Using \b rule_rleja nodes but doubling the nodes every 4 levels, reduces the Lebesgue constant. rule_rlejadouble4, //! \brief Same as \b rule_rleja but using only odd levels, quadrature is more stable. rule_rlejaodd, //! \brief Similar \b sequence to \b rule_rleja but with nodes strictly in the interior. rule_rlejashifted, //! \brief Same as \b rule_rlejashifted but using only even levels, quadrature is more stable. rule_rlejashiftedeven, //! \brief Same as \b rule_rlejashifted but doubling the number of nodes per level, which reduced the Lebesgue constant. rule_rlejashifteddouble, //! \brief A greedy \b sequence rule with nodes placed at the maximum of the Lebesgue function. rule_maxlebesgue, //! \brief Same as \b rule_maxlebesgue but using only odd levels, quadrature is more stable. rule_maxlebesgueodd, //! \brief A greedy \b sequence rule with nodes added to minimize the Lebesgue constant. rule_minlebesgue, //! \brief Same as \b rule_minlebesgue but using only odd levels, quadrature is more stable. rule_minlebesgueodd, //! \brief A greedy \b sequence rule with nodes added to minimize the norm of the surplus operator. rule_mindelta, //! \brief Same as \b rule_mindelta but using only odd levels, quadrature is more stable. rule_mindeltaodd, //! \brief Non-nested rule but optimized for integration. rule_gausslegendre, //! \brief Same as \b rule_gausslegendre but using only odd levels, partially mitigates the non-nested issues. rule_gausslegendreodd, //! \brief Nested rule that is optimized for integration, probably the best integration rule in more than 2 dimensions. rule_gausspatterson, //! \brief Non-nested rule optimized for integral of the form \f$ \int_{a}^{b} f(x) / \sqrt{(b - x)(x - a)} dx \f$. rule_gausschebyshev1, //! \brief Same as \b rule_gausschebyshev1 but using only odd levels, partially mitigates the non-nested issues. rule_gausschebyshev1odd, //! \brief Non-nested rule optimized for integral of the form \f$ \int_{a}^{b} f(x) \sqrt{(b - x)(x - a)} dx \f$. rule_gausschebyshev2, //! \brief Same as \b rule_gausschebyshev2 but using only odd levels, partially mitigates the non-nested issues. rule_gausschebyshev2odd, //! \brief Non-nested rule optimized for integral of the form \f$ \int_{a}^{b} f(x) (b - x)^\alpha (x - a)^\alpha dx \f$. rule_gaussgegenbauer, //! \brief Same as \b rule_gaussgegenbauer but using only odd levels, partially mitigates the non-nested issues. rule_gaussgegenbauerodd, //! \brief Non-nested rule optimized for integral of the form \f$ \int_{a}^{b} f(x) (b - x)^\alpha (x - a)^\beta dx \f$. rule_gaussjacobi, //! \brief Same as \b rule_gaussjacobi but using only odd levels, partially mitigates the non-nested issues. rule_gaussjacobiodd, //! \brief Non-nested rule optimized for integral of the form \f$ \int_{a}^{\infty} f(x) (x - a)^\alpha \exp \left(-b (x - a) \right) dx \f$. rule_gausslaguerre, //! \brief Same as \b rule_gausslaguerre but using only odd levels, partially mitigates the non-nested issues. rule_gausslaguerreodd, //! \brief Non-nested rule optimized for integral of the form \f$ \int_{-\infty}^{\infty} f(x) (x - a)^\alpha \exp \left(-b (x - a)^2 \right) dx \f$. rule_gausshermite, //! \brief Same as \b rule_gausshermite but using only odd levels, partially mitigates the non-nested issues. rule_gausshermiteodd, //! \brief User provided rule, nodes and weights must be provided with a separate file. rule_customtabulated, // Piece-Wise rules //! \brief Nested rule with a hierarchy of uniformly distributed nodes and functions with compact support. rule_localp, //! \brief Variation of \b rule_localp assuming the model is zero at the domain boundary. rule_localp0, //! \brief Variation of \b rule_localp using increased support in exchange for higher order basis (better for smoother functions). rule_semilocalp, //! \brief Variation of \b rule_localp focusing nodes on the boundary instead of the interior. rule_localpb, //! \brief Wavelet basis with uniformly distributed nodes (primarily for internal use). rule_wavelet, //! \brief Trigonometric basis with uniformly distributed nodes (primarily for internal use). rule_fourier }; //! \brief Refinement strategy for local polynomial and wavelet grids. //! \ingroup SGEnumerates //! \par Local Hierarchical Approximation //! The nodes and basis functions used in local polynomial and wavelet sparse grid form a complex multidimensional hierarchy, //! where each node is associated with one or more parents and children in each direction. In both cases, the support of the //! children is (almost always) smaller than the support of the patent and in the polynomial case, the support of the //! children nodes is strictly contained within the support of the parent. //! //! \par //! The interpolant is expressed as a linear combination of basis functions with coefficients computed so that the //! interpolant matches the model values at the sparse gird nodes. The coefficients are thus indicators of the local //! approximation error and (in the asymptotic limit) the coefficients decrease when going form a parent to a child. //! //! \par Convergence Criteria //! Using the local error estimator, the sparse grid approximation has reached desired tolerance //! when all nodes with missing children //! have coefficients with absolute values smaller than the tolerance. This is a necessary and not a sufficient condition //! an is heavily reliant on the assumption of monotonic decay of the coefficients; however, in practical situations this is a good //! way to construct an adaptive grid that captures the behavior of the target model while minimizing the number of nodes. //! //! \par Adaptive Refinement //! The idea of refinement is to start with a coarse spars grid and gradually add children of existing nodes, but only if the nodes //! have a large hierarchical coefficient. The nodes are added until the coefficients of all nodes with with missing children //! drop below user specified tolerance. The refinement types listed below differ in the way that the parents and children //! are selected in the adaptive construction, and whether local anisotropy is considered. //! //! \par Refinement Types //! Each nodes is associated with multiple parents corresponding //! to different directions, even if each one dimensional node has only a single parent. Thus, over several iterations //! and if the hierarchical coefficients do not decay monotonically, it is possible to have nodes with missing parents //! for some directions, which can hinter convergence. Furthermore, the hierarchical coefficients do not carry any //! information regarding potential local anisotropy and a second refinement criteria can be employed, where an interpolant //! is constructed using only the data associated with the nodes that lay in a single direction. Children and/or parents of //! a node are added to the grid only when both the isotropic and anisotropic error indicators exceed the user specified tolerance. //! //! \par //! The \b classic refinement strategy adds only the children for the nodes with hierarchical coefficient that exceed the //! user provided tolerance (local anisotropy and missing parents are ignored). The \b parents \b first and \b fds //! strategies loop for missing parents and add the parents before adding children, which usually improves stability //! when compared to adding only children. The \b direction \b selective and \b fds strategies consider local anisotropy //! which can reduce the number of required model evaluations, but can also lead to decrease in stability. //! The \b stable refinement is both isotropic and maintains lower-complete structures, i.e., no point has a missing //! parent. While the most stable, the \b stable strategy can lead to significant oversampling. //! //! Details regarding adaptive hierarchical sparse grids construction and children-parent relations can be found in: \n //! M. Stoyanov, //! Adaptive Sparse Grid Construction in a Context of Local Anisotropy and Multiple Hierarchical Parents,\n //! Sparse Grids and Applications - Miami 2016 pp 175-199.\n //! Also in: Tech Report ORNL/TM-2013/384. enum TypeRefinement{ //! \brief Isotropic refinement using only the children and disregarding missing parents. refine_classic, //! \brief Isotropic refinement adding children only if the parents are already included. refine_parents_first, //! \brief Anisotropic refinement using only the children and disregarding missing parents. refine_direction_selective, //! \brief Anisotropic refinement adding children only if the parents are already included. refine_fds, //! \brief Isotropic refinement that ensures the points maintain lower-complete structures. refine_stable, //! \brief Null method, should \b never be used as input. refine_none }; /*! * \ingroup SGEnumerates * \brief Modes of acceleration. * * \par Acceleration Context * Each Tasmanian object creates a Tasmanian acceleration context that operate on one of several modes * (depending on the external libraries being used) and the context will remain persistent on read/write, * make/clean, and move operation. The context cannot be copied from one object to another. * For example, an object is created and CUDA acceleration is enabled, then makeLocalPolynomial() is called, * then the Nvidia GPU device will be used to speed the different operation of the grid, if then read() * is called, a new grid will be loaded from a file and regardless of the type of grid the GPU will still * be in use by the object. If the grid is copied, both source and destination will retain their original * acceleration contexts and only the grid data (e.g., points and model values) will be copied. * * \par Utilizing Accelerated Libraries * Each Tasmanian operation that has a (potentially) significant computational cost is a candidate for acceleration. * Currently, OpenMP is uses throughout the Tasmanian code is essentially all potential places and * the evaluateBatch() methods associated with all types of grids can be accelerated with BLAS and CUDA. * The BLAS/LAPACK and CUDA acceleration is also available in other select methods, e.g., * TasmanianSparseGrid::loadNeededPoints() for local polynomial and wavelet grid. * * \par OpenMP and Thread Count * If enabled, OpenMP is ubiquitous throughout Tasmanian in almost all computationally expensive operations. * The acceleration mode can be disabled only at compile time; however, the standard OpenMP options * are respected at runtime, e.g., the method omp_set_num_threads() and OMP_NUM_THREADS environment variable, * if either is set to 1, Tasmanian will use only one hardware thread. * * \par Acceleration Mode None * In this mode, Tasmanian will forego the use of third party libraries (other then OpenMP) and the algorithms * will run in the most memory conservative way. Due to improved data-locality and depending on the hardware architecture, * the TasGrid::accel_none mode can be the fastest mode for small grids with few points and few outputs. * * \par Memory Management and Persistent Data * The use of third party libraries requires that matrices are explicitly formed even when that can be avoided * in the no-acceleration mode. Furthermore, operations that are called repeatedly, i.e., evaluateBatch() used * in the context of DREAM sampling, will also cache matrices that can be reused in multiple calls. * The cache is particularly an issue for the various GPU modes since the memory on the accelerator devices is * sometimes limited. One-shot calls, such as loadNeededPoints(), will not use cache that persistent after * the call to the method. * The cache can always be cleared by either changing the grid (creating a new grid or loading more points * as part of iterative refinement), or by switching to mode TasGrid::accel_none and then back to one of the fast modes. * * \par Memory usage for Evaluate Batch * Global, Sequence, Fourier and Wavelet grids operate only with dense matrices and require one persistent * matrix of size \b getNumPoints() times \b getNumOutputs(), one temporary matrix of size \b getNumPoints() * times \b num_x, and user provided matrix to hold the result of size \b getNumOutputs() times \b num_x. * The batch size \b num_x can be adjusted to accommodate memory constraints, but better performance * is usually achieved when \b num_x is large due to the increased opportunities to parallelize. * Local polynomial grids (when using the default sparse mode) will use sparse representation of * the transient matrix and thus the memory usage strongly depends on the graph structure of the grid. * In addition, all grids use a relatively small amount of GPU cache which depends on the number of underlying * tensors and the specific graph structure of the grid. * * \par Defaults * If \b Tasmanian_ENABLE_BLAS is enabled in CMake, then TasGrid::accel_cpu_blas will be the default acceleration mode, * otherwise the default mode is TasGrid::accel_none. * The TasGrid::accel_gpu_default uses the first available in the list: * - TasGrid::accel_gpu_magma * - TasGrid::accel_gpu_cuda * - TasGrid::accel_cpu_blas * - TasGrid::accel_none * * \par * The defaults and fallback extend to all methods that could use accelerations. For example, if GPU acceleration * has been enabled, but the current method does not have a GPU implementation, the "next-best" BLAS implementation * will be used instead. Thus, the use of BLAS and LAPACK can be disabled either at compile time or with accel_none, * but not with accel_gpu_cuda. * * \par * Note that regardless of the acceleration mode, all evaluate methods will to generate output that * is identical up to rounding error. By design, the \b TasmanianSparseGrid::enableAcceleration() can be called * with any acceleration type regardless whether it has been enabled by CMake. * In order to facilitate code portability, Tasmanian implements sane fall-back * modes so that "the next best mode" will be automatically selected if the desired mode is not present. Specifically, * missing MAGMA will fallback to CUDA, missing CUDA will fallback to BLAS, and missing BLAS will fallback to none. * * \par Thread Safety and Const-correctness * Using mode TasGrid::accel_none, Tasmanian will not use any transient data-structures and the code is const-correct * in the strictest definition, i.e., any two const-methods can be called concurrently from any two threads * and will produce the correct result. * Other modes use transient cache (with the C++ keyword mutable), which will be generated after the first call * to the method and will be reused in follow on call. Thus, the first call is not thread-safe, while the follow on * calls are strictly const-correct in the same sense as TasGrid::accel_none. * Also note that some third party libraries can have additional restrictions, e.g., concurrent calls to OpenBLAS * are not thread-safe unless the library is build with a specific flag. The CUDA and MAGMA libraries appear * to not have such limitations. * * \par Library Handles * The GPU libraries use context handles to manage metadata such as active device and device pointer type. * By default, Tasmanian will automatically create the handles whenever needed and will destroy them whenever * the object is destroyed or the acceleration mode is updated. * However, Tasmanian also provides an API where the user can provide the corresponding handles: * \code * // Nvidia CUDA framework * grid.setCuBlasHandle(cublas_handle); * grid.setCuSparseHandle(cusparse_handle); * grid.setCuSolverHandle(cusolverdn_handle); * // AMD ROCm framework * grid.setRocBlasHandle(rocblas_handle); * grid.setRocSparseHandle(rocsparse_handle); * // Intel DPC++ framework * grid.setSycleQueue(pointer_to_sycl_queue); * \endcode * - Each handle must be a valid, i.e., already created by the corresponding API call and must be associated * with the currently selected GPU device ID. * - Tasmanian assumes that the pointer mode is "host pointer" (for Nvidia and AMD) and if a different mode is set in-between Tasmanian * API calls, the mode must be reset before the next Tasmanian call. * - The SYCL queue is accepted as a pointer, which is different then the usual SYCL approach but it is consistent within the Tasmanian API. * - The methods interact directly with the TPL API and hence the methods do not have fallback modes * if GPU has not been enabled. */ enum TypeAcceleration{ //! \brief Usually the slowest mode, uses only OpenMP multi-threading, but optimized for memory and could be the fastest mode for small problems. accel_none, //! \brief Default (if available), uses both BLAS and LAPACK libraries. accel_cpu_blas, //! \brief Equivalent to the first available from MAGMA, CUDA, BLAS, or none. accel_gpu_default, //! \brief Mixed usage of the CPU (OpenMP) and GPU libraries. accel_gpu_cublas, //! \brief Similar to the cuBLAS option but also uses a set of Tasmanian custom GPU kernels. accel_gpu_cuda, //! \brief Same the CUDA option but uses the UTK MAGMA library for the linear algebra operations. accel_gpu_magma }; /*! * \ingroup SGEnumerates * \brief At the front API, the HIP and CUDA options are equivalent, see TasGrid::TypeAcceleration. */ constexpr TypeAcceleration accel_gpu_hip = accel_gpu_cuda; /*! * \ingroup SGEnumerates * \brief At the front API, the HIP and CUDA options are equivalent, see TasGrid::TypeAcceleration. */ constexpr TypeAcceleration accel_gpu_rocblas = accel_gpu_cublas; } #endif TASMANIAN-8.1/SparseGrids/tsgGridCore.hpp000066400000000000000000000171511470551176200200650ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_BASE_CLASS_HPP #define __TSG_BASE_CLASS_HPP /*! * \internal * \file tsgGridCore.hpp * \brief Definition for the base grid class. * \author Miroslav Stoyanov * \ingroup TasmanianSets * * Definition of the BaseCanonicalGrid class used by all grids. * \endinternal */ #include "tsgDConstructGridGlobal.hpp" #include "tsgCudaLoadStructures.hpp" #include "tsgHierarchyManipulator.hpp" #ifndef __TASMANIAN_DOXYGEN_SKIP namespace TasGrid{ class BaseCanonicalGrid{ public: BaseCanonicalGrid(AccelerationContext const *acc) : acceleration(acc), num_dimensions(0), num_outputs(0){} BaseCanonicalGrid(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, MultiIndexSet &&cpoints, MultiIndexSet &&cneeded, StorageSet &&cvalues) : acceleration(acc), num_dimensions(cnum_dimensions), num_outputs(cnum_outputs), points(std::forward(cpoints)), needed(std::forward(cneeded)), values(std::forward(cvalues)){} BaseCanonicalGrid(AccelerationContext const *acc, BaseCanonicalGrid const &other, int ibegin, int iend) : acceleration(acc), num_dimensions(other.num_dimensions), num_outputs(iend - ibegin), points(other.points), needed(other.needed), values((iend - ibegin == other.num_outputs) ? other.values : other.values.splitValues(ibegin, iend)) {} virtual ~BaseCanonicalGrid() = default; virtual bool isGlobal() const{ return false; } virtual bool isSequence() const{ return false; } virtual bool isLocalPolynomial() const{ return false; } virtual bool isWavelet() const{ return false; } virtual bool isFourier() const{ return false; } int getNumDimensions() const{ return num_dimensions; } int getNumOutputs() const{ return num_outputs; } virtual TypeOneDRule getRule() const = 0; int getNumLoaded() const{ return (num_outputs == 0) ? 0 : points.getNumIndexes(); } int getNumNeeded() const{ return needed.getNumIndexes(); } int getNumPoints() const{ return ((points.empty()) ? needed.getNumIndexes() : points.getNumIndexes()); } const int* getPointIndexes() const{ return ((points.empty()) ? needed.getIndex(0) : points.getIndex(0)); } virtual void write(std::ostream&, bool) const = 0; virtual void getLoadedPoints(double *x) const = 0; virtual void getNeededPoints(double *x) const = 0; virtual void getPoints(double *x) const = 0; virtual void getQuadratureWeights(double weights[]) const = 0; virtual void getInterpolationWeights(const double x[], double weights[]) const = 0; virtual void getDifferentiationWeights(const double x[], double weights[]) const = 0; virtual void loadNeededValues(const double *vals) = 0; const double* getLoadedValues() const{ return (points.empty()) ? nullptr : values.getValues(0); } virtual void evaluate(const double x[], double y[]) const = 0; virtual void integrate(double q[], double *conformal_correction) const = 0; virtual void differentiate(const double x[], double jacobian[]) const = 0; virtual void evaluateBatch(const double x[], int num_x, double y[]) const = 0; virtual void evaluateBatchGPU(const double[], int, double[]) const = 0; virtual void evaluateBatchGPU(const float[], int, float[]) const = 0; virtual void evaluateHierarchicalFunctionsGPU(const double[], int, double[]) const = 0; virtual void evaluateHierarchicalFunctionsGPU(const float[], int, float[]) const = 0; virtual void clearRefinement() = 0; virtual void mergeRefinement() = 0; virtual void beginConstruction() = 0; virtual void writeConstructionData(std::ostream&, bool) const = 0; virtual void readConstructionData(std::istream&, bool) = 0; virtual void loadConstructedPoint(const double[], const std::vector &) = 0; virtual void loadConstructedPoint(const double[], int, const double[]) = 0; virtual void finishConstruction() = 0; virtual void evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const = 0; // add acceleration here virtual std::vector getSupport() const{ return std::vector(Utils::size_mult(getNumPoints(), getNumDimensions()), 2.0); } virtual void setHierarchicalCoefficients(const double c[]) = 0; virtual void integrateHierarchicalFunctions(double integrals[]) const = 0; virtual void updateAccelerationData(AccelerationContext::ChangeType change) const = 0; protected: AccelerationContext const *acceleration; int num_dimensions, num_outputs; MultiIndexSet points; MultiIndexSet needed; StorageSet values; }; // For purposes of reading grids with older file formats // Specialize the reader class for each grid type // Befriend the reader class and each grid type template struct GridReaderVersion5{ // 5 refers to the file format version, not the Tasmanian version template static std::unique_ptr read(AccelerationContext const*, std::istream &){ return std::unique_ptr(); } }; // Factory reader method that instantiates the GridReaderVersion5 class template std::unique_ptr readGridVersion5(AccelerationContext const *acc, std::istream &is, iomode){ return GridReaderVersion5::template read(acc, is); } } #endif #endif TASMANIAN-8.1/SparseGrids/tsgGridFourier.cpp000066400000000000000000001420321470551176200206000ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_FOURIER_CPP #define __TASMANIAN_SPARSE_GRID_FOURIER_CPP #include "tsgGridFourier.hpp" #include "tsgTPLWrappers.hpp" namespace TasGrid{ template void GridFourier::write(std::ostream &os) const{ if (iomode == mode_ascii){ os << std::scientific; os.precision(17); } IO::writeNumbers(os, num_dimensions, num_outputs); tensors.write(os); active_tensors.write(os); if (!active_w.empty()) IO::writeVector(active_w, os); IO::writeFlag(!points.empty(), os); if (!points.empty()) points.write(os); IO::writeFlag(!needed.empty(), os); if (!needed.empty()) needed.write(os); IO::writeVector(max_levels, os); if (num_outputs > 0){ values.write(os); IO::writeFlag((fourier_coefs.getNumStrips() != 0), os); if (!fourier_coefs.empty()) fourier_coefs.writeVector(os); } IO::writeFlag(!updated_tensors.empty(), os); if (!updated_tensors.empty()){ updated_tensors.write(os); updated_active_tensors.write(os); IO::writeVector(updated_active_w, os); } } template void GridFourier::write(std::ostream &) const; template void GridFourier::write(std::ostream &) const; void GridFourier::makeGrid(int cnum_dimensions, int cnum_outputs, int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ setTensors(selectTensors((size_t) cnum_dimensions, depth, type, anisotropic_weights, level_limits), cnum_outputs); } GridFourier::GridFourier(AccelerationContext const *acc, GridFourier const *fourier, int ibegin, int iend) : BaseCanonicalGrid(acc, *fourier, ibegin, iend), wrapper(fourier->wrapper), tensors (fourier->tensors), active_tensors(fourier->active_tensors), active_w (fourier->active_w), updated_tensors (fourier->updated_tensors), updated_active_tensors(fourier->updated_active_tensors), updated_active_w (fourier->updated_active_w), max_levels(fourier->max_levels), fourier_coefs((num_outputs == fourier->num_outputs) ? fourier->fourier_coefs : fourier->fourier_coefs.splitData(ibegin, iend)), max_power(fourier->max_power){ if (fourier->dynamic_values){ dynamic_values = Utils::make_unique(*fourier->dynamic_values); if (num_outputs != fourier->num_outputs) dynamic_values->restrictData(ibegin, iend); } } void GridFourier::updateGrid(int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ if ((num_outputs == 0) || points.empty()){ makeGrid(num_dimensions, num_outputs, depth, type, anisotropic_weights, level_limits); }else{ clearRefinement(); updated_tensors = selectTensors((size_t) num_dimensions, depth, type, anisotropic_weights, level_limits); MultiIndexSet new_tensors = updated_tensors - tensors; if (!new_tensors.empty()){ updated_tensors += tensors; proposeUpdatedTensors(); } } } MultiIndexSet GridFourier::selectTensors(size_t dims, int depth, TypeDepth type, const std::vector &anisotropic_weights, std::vector const &level_limits) const{ return (OneDimensionalMeta::isExactLevel(type)) ? MultiIndexManipulations::selectTensors(dims, depth, type, [&](int i) -> int{ return i; }, anisotropic_weights, level_limits) : MultiIndexManipulations::selectTensors(dims, depth, type, [&](int i) -> int{ return OneDimensionalMeta::getIExact(i, rule_fourier); }, anisotropic_weights, level_limits); } void GridFourier::setTensors(MultiIndexSet &&tset, int cnum_outputs){ clearGpuNodes(); clearGpuCoefficients(); points = MultiIndexSet(); values = StorageSet(); active_w.clear(); fourier_coefs.clear(); tensors = std::move(tset); num_dimensions = (int) tensors.getNumDimensions(); num_outputs = cnum_outputs; max_levels = MultiIndexManipulations::getMaxIndexes(tensors); wrapper = OneDimensionalWrapper(*std::max_element(max_levels.begin(), max_levels.end()), rule_fourier, 0.0, 0.0); MultiIndexManipulations::computeActiveTensorsWeights(tensors, active_tensors, active_w); needed = MultiIndexManipulations::generateNestedPoints(tensors, [&](int l) -> int{ return wrapper.getNumPoints(l); }); if (num_outputs == 0){ points = std::move(needed); needed = MultiIndexSet(); }else{ values.resize(num_outputs, needed.getNumIndexes()); } max_power = MultiIndexManipulations::getMaxIndexes(((points.empty()) ? needed : points)); } void GridFourier::proposeUpdatedTensors(){ wrapper = OneDimensionalWrapper(updated_tensors.getMaxIndex(), rule_fourier, 0.0, 0.0); MultiIndexManipulations::computeActiveTensorsWeights(updated_tensors, updated_active_tensors, updated_active_w); needed = MultiIndexManipulations::generateNestedPoints(updated_tensors, [&](int l) -> int{ return wrapper.getNumPoints(l); }) - points; } void GridFourier::acceptUpdatedTensors(){ if (points.empty()){ clearGpuNodes(); // the points and needed will change, clear the cache points = std::move(needed); needed = MultiIndexSet(); }else if (!needed.empty()){ points += needed; needed = MultiIndexSet(); tensors = std::move(updated_tensors); updated_tensors = MultiIndexSet(); active_tensors = std::move(updated_active_tensors); updated_active_tensors = MultiIndexSet(); active_w = std::move(updated_active_w); updated_active_w = std::vector(); max_levels = MultiIndexManipulations::getMaxIndexes(tensors); } } void GridFourier::loadNeededValues(const double *vals){ clearGpuCoefficients(); // changing values and Fourier coefficients, clear the cache if (points.empty() || needed.empty()){ values.setValues(vals); }else{ values.addValues(points, needed, vals); } acceptUpdatedTensors(); calculateFourierCoefficients(); max_power = MultiIndexManipulations::getMaxIndexes(points); } void GridFourier::getLoadedPoints(double *x) const{ MultiIndexManipulations::indexesToNodes(points, wrapper, x); } void GridFourier::getNeededPoints(double *x) const{ MultiIndexManipulations::indexesToNodes(needed, wrapper, x); } void GridFourier::getPoints(double *x) const{ if (points.empty()){ getNeededPoints(x); }else{ getLoadedPoints(x); }; } std::vector> GridFourier::generateIndexingMap() const{ // The internal point-indexing of Tasmanian goes 0, 1/3, 2/3, 1/9, 2/9, 4/9 .... // Fourier transform (and coefficients) need spacial order 0, 1/9, 2/9, 3/9=1/3, ... // Create a map, where at level 0: 0 -> 0, level 1: 0 1 2 -> 0 1 2, level 2: 0 1 2 3 4 5 6 7 8 -> 0 3 4 1 5 6 2 7 8 // The map takes a point from previous map and adds two more points ... // Thus, a spacial point i on level l is Tasmanian point index_map[l][i] int maxl = 1 + active_tensors.getMaxIndex(); std::vector> index_map(maxl); index_map[0].resize(1, 0); int c = 1; for(int l=1; l Second // The Second -> Third indexing is done per-tensor, where the non-negative exponents are associated with coefficients // going from left to right (in the order of the Fourier coefficients), while the negative coefficients go // in reverse right to left order "int rj = (p[j] % 2 == 0) ? (p[j]+1) / 2 : num_oned_points[j] - (p[j]+1) / 2;" int num_points = getNumPoints(); MultiIndexSet &work = (points.empty()) ? needed : points; std::vector> index_map = generateIndexingMap(); fourier_coefs = Data2D(num_outputs, 2 * num_points); for(int n=0; n num_oned_points(num_dimensions); std::vector cnum_oned_points(num_dimensions, 1); // cumulative number of points for(int j=0; j=0; j--) cnum_oned_points[j] = num_oned_points[j+1] * cnum_oned_points[j+1]; std::vector>> tensor_data(num_tensor_points); std::vector p(num_dimensions); for(int i=0; i=0; j--){ // here p[] is the Tasmanian index of index from real space i (t % num_oned_points[j]) p[j] = index_map[levels[j]][t % num_oned_points[j]]; t /= num_oned_points[j]; } //refs[i] = ; // refs[i] is the index of Tasmanian (index set) corresponding to real index "i" double const *v = values.getValues(work.getSlot(p)); tensor_data[i] = std::vector>(v, v + num_outputs); } TasmanianFourierTransform::fast_fourier_transform(tensor_data, num_oned_points); double tensorw = ((double) active_w[n]) / ((double) num_tensor_points); for(int i=0; i=0; j--){ // here rj is the real multi-index corresponding to "i" p[j] = t % num_oned_points[j]; int rj = (p[j] % 2 == 0) ? (p[j]+1) / 2 : num_oned_points[j] - (p[j]+1) / 2; // +/- index r += rj * cnum_oned_points[j]; t /= num_oned_points[j]; } t = work.getSlot(p); // holds the Tasmanian index corresponding to real index p // Combine with tensor weights double *fc_real = fourier_coefs.getStrip(t); double *fc_imag = fourier_coefs.getStrip(t + num_points); for(auto d : tensor_data[r]){ *fc_real++ += tensorw * d.real(); *fc_imag++ += tensorw * d.imag(); } } } } void GridFourier::getInterpolationWeights(const double x[], double weights[]) const { // if Fourier coefficient are c, Data from the target function is f, and values of the basis functions are b // then we have c = A * f (where A is both the Fourier transform and the reindexing) // and the value of the interpolant is result = = = , where A^* is conjugate transpose // However, we consider only the real values (the complex ones add-up to zero), thus we really need A^T (regular transpose) // The Fourier transform is symmetric with respect to regular transpose, which leaves only the indexing // Take the basis functions, reindex and reorder to a data strucutre, take FFT, reindex and reorder into the weights // // // This code uses a O(N) algorithm instead of an O(N log N) FFT. On a 1D tensor with N=3^l points, we must compute the // Fourier transform of // {x_n} = e^(2 \pi i x * {0,1,2, ..., (N-1)/2, -(N-1)/2, ..., -2, -1}). (componentwise operations) // The FFT is // X[m] = \sum_{j=0}^{N-1} e^{-2 \pi i j m / N} x_n // = ( \sum_{j=0}^{(N-1)/2} e^{-2 \pi i j m / N} e^{2 \pi i x j} ) // + ( \sum_{j=1}^{(N-1)/2} e^{2 \pi i j m / N} e^{-2 \pi i x j} ) // = 2 * Re[ \sum_{j=0}^{(N-1)/2} e^{-2 \pi i j m / N} e^{2 \pi i x j} ] - 1 // = 2 * Re[ \sum_{j=0}^{(N-1)/2} (e^{2 \pi i (x-m/N)})^j ] - 1 // = 2 * Re[ \frac{1 - e^{2 \pi i (x-m/N) (N+1)/2}}{1 - e^{2 \pi i (x-m/N)}} ] - 1 // The cost is mainly driven by evaluating the complex exponentials, so we compute what we can at the beginning and // park it in a cache. const MultiIndexSet &work = (points.empty()) ? needed : points; std::vector> index_map = generateIndexingMap(); std::fill_n(weights, work.getNumIndexes(), 0.0); // compute what we need for e^{-2 \pi i m / N} int maxl = active_tensors.getMaxIndex() + 1; std::vector>> expcache(maxl); for(int i=0; i(1.0, 0.0); double theta = -2.0 * Maths::pi / ((double) num_oned_points); // step angle std::complex step(std::cos(theta), std::sin(theta)); for(int j=1; j>> numerator_cache(num_dimensions); for(int k=0; k(std::cos(theta), std::sin(theta)); for(int j=1; j num_oned_points(num_dimensions); for(int j=0; j p(num_dimensions); double tensorw = ((double) active_w[n]) / ((double) num_tensor_points); for(int i=0; i=0; j--){ // here p is the index of the spacial point in Tasmanian indexing int r = t % num_oned_points[j]; int offset = (r*(num_oned_points[j]+1)/2) % num_oned_points[j]; // in order to fetch reduced form of (N+1)*r/(2*N) if (std::abs(1.0 - (numerator_cache[j][0] * expcache[levels[j]][r]).real()) < Maths::num_tol){ // we're evaluating the basis functions at a node; take care of zero-divide fftprod *= num_oned_points[j]; }else{ fftprod *= 2.0 * ( (1.0 - numerator_cache[j][levels[j]] * expcache[levels[j]][offset]) / (1.0 - numerator_cache[j][0] * expcache[levels[j]][r]) ).real() - 1.0; } p[j] = index_map[levels[j]][r]; t /= num_oned_points[j]; } weights[work.getSlot(p)] += (tensorw * fftprod); } } } void GridFourier::getQuadratureWeights(double weights[]) const{ // When integrating the Fourier series on a tensored grid, all the // nonzero modes vanish, and we're left with the normalized Fourier // coeff for e^0 (sum of the data divided by number of points) const MultiIndexSet &work = (points.empty()) ? needed : points; std::fill_n(weights, work.getNumIndexes(), 0.0); for(int n=0; n refs = MultiIndexManipulations::referencePoints(levels, wrapper, work); double tensorw = ((double) active_w[n]) / ((double) num_tensor_points); for(int i=0; i> index_map = generateIndexingMap(); std::fill_n(weights, work.getNumIndexes(), 0.0); // Cache exp(-2 * Ï€ * I * m / 3^{l}) for every (m, l) where N = 3^l. int maxl = active_tensors.getMaxIndex() + 1; std::vector>> shift_cache(maxl); for(int i=0; i(1.0, 0.0); double theta = -2.0 * Maths::pi / ((double) num_oned_points); std::complex step(std::cos(theta), std::sin(theta)); for(int j=1; j>> slope_cache(num_dimensions); for(int k=0; k(std::cos(theta), std::sin(theta)); for(int j=1; j exp_Ibx = slope_cache[d][0] * shift_cache[l][r]; if (std::abs(1.0 - exp_Ibx.real()) <= Maths::num_tol) return (double) N; int offset = (r * (N + 1) / 2) % N; std::complex exp_Iax = slope_cache[d][l] * shift_cache[l][offset]; return 2.0 * ((1.0 - exp_Iax) / (1.0 - exp_Ibx)).real() - 1.0; }; // This lambda is the same as get_fft_val(), but returns the FFT derivative. auto get_fft_diff_val = [&](const int d, const int l, int N, int r) { std::complex exp_Ibx = slope_cache[d][0] * shift_cache[l][r]; if (std::abs(1.0 - exp_Ibx.real()) <= Maths::num_tol) return 0.0; double N_dbl = (double) N; double slope_b = 2.0 * Maths::pi; double slope_a = Maths::pi * (N_dbl + 1.0); int offset = (r * (N + 1) / 2) % N; std::complex exp_Iax = slope_cache[d][l] * shift_cache[l][offset]; std::complex exp_Ia_sub_Ib = exp_Iax * std::conj(exp_Ibx); // q1 below is equivalent to [2.0 - 2.0 * cos(b)], but is more computationally stable since it combines // both real and imaginary parts. double q0 = std::abs(1.0 - exp_Ibx); double q1 = q0 * q0; double s1 = (slope_a * exp_Iax.imag() + slope_b * exp_Ibx.imag() - (slope_a - slope_b) * exp_Ia_sub_Ib.imag()) * q1; double s2 = (1.0 - exp_Iax.real() - exp_Ibx.real() + exp_Ia_sub_Ib.real()) * 2.0 * slope_b * exp_Ibx.imag(); return 2.0 * (s1 - s2) / (q1 * q1); }; // Compute the weights for each tensor. for(int n=0; n num_oned_points(num_dimensions); for(int j=0; j p(num_dimensions); double tensorw = ((double) active_w[n]) / ((double) num_tensor_points); for(int i=0; i fft_vals(num_dimensions); std::vector fft_diff_vals(num_dimensions); for(int j=num_dimensions-1; j>=0; j--) { int r = t % num_oned_points[j]; fft_vals[j] = get_fft_val(j, levels[j], num_oned_points[j], r); fft_diff_vals[j] = get_fft_diff_val(j, levels[j], num_oned_points[j], r); p[j] = index_map[levels[j]][r]; t /= num_oned_points[j]; } for(int k=0; k wreal(num_points); std::vector wimag(num_points); computeBasis(points, x, wreal.data(), wimag.data()); for(int i=0; imode){ case accel_gpu_magma: case accel_gpu_cuda: { acceleration->setDevice(); GpuVector gpu_x(acceleration, num_dimensions, num_x, x), gpu_y(acceleration, num_outputs, num_x); evaluateBatchGPU(gpu_x.data(), num_x, gpu_y.data()); gpu_y.unload(acceleration, y); break; } case accel_gpu_cublas: { acceleration->setDevice(); loadGpuCoefficients(); Data2D wreal; Data2D wimag; evaluateHierarchicalFunctionsInternal(x, num_x, wreal, wimag); int num_points = points.getNumIndexes(); GpuVector gpu_real(acceleration, wreal.begin(), wreal.end()), gpu_imag(acceleration, wimag.begin(), wimag.end()), gpu_y(acceleration, num_outputs, num_x); TasGpu::denseMultiply(acceleration, num_outputs, num_x, num_points, 1.0, gpu_cache->real, gpu_real, 0.0, gpu_y.data()); TasGpu::denseMultiply(acceleration, num_outputs, num_x, num_points, -1.0, gpu_cache->imag, gpu_imag, 1.0, gpu_y.data()); gpu_y.unload(acceleration, y); break; } case accel_cpu_blas: { int num_points = points.getNumIndexes(); Data2D wreal; Data2D wimag; if (num_x > 1){ evaluateHierarchicalFunctionsInternal(x, num_x, wreal, wimag); }else{ // work-around small OpenMP penalty wreal = Data2D(num_points, 1); wimag = Data2D(num_points, 1); computeBasis(points, x, wreal.data(), wimag.data()); } TasBLAS::denseMultiply(num_outputs, num_x, num_points, 1.0, fourier_coefs.getStrip(0), wreal.data(), 0.0, y); TasBLAS::denseMultiply(num_outputs, num_x, num_points, -1.0, fourier_coefs.getStrip(num_points), wimag.data(), 1.0, y); break; } default: { Utils::Wrapper2D xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(num_outputs, y); #pragma omp parallel for for(int i=0; i void GridFourier::evaluateBatchGPUtempl(const T gpu_x[], int cpu_num_x, T gpu_y[]) const{ loadGpuCoefficients(); GpuVector gpu_real, gpu_imag; evaluateHierarchicalFunctionsInternalGPU(gpu_x, cpu_num_x, gpu_real, gpu_imag); int num_points = points.getNumIndexes(); auto& ccache = getGpuCache(); TasGpu::denseMultiply(acceleration, num_outputs, cpu_num_x, num_points, 1.0, ccache->real, gpu_real, 0.0, gpu_y); TasGpu::denseMultiply(acceleration, num_outputs, cpu_num_x, num_points, -1.0, ccache->imag, gpu_imag, 1.0, gpu_y); } void GridFourier::evaluateBatchGPU(const double gpu_x[], int cpu_num_x, double gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridFourier::evaluateBatchGPU(const float gpu_x[], int cpu_num_x, float gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridFourier::evaluateHierarchicalFunctionsGPU(const double gpu_x[], int num_x, double gpu_y[]) const{ loadGpuNodes(); TasGpu::devalfor(acceleration, num_dimensions, num_x, max_levels, gpu_x, gpu_cache->num_nodes, gpu_cache->points, gpu_y, nullptr); } void GridFourier::evaluateHierarchicalFunctionsGPU(const float gpu_x[], int num_x, float gpu_y[]) const{ loadGpuNodes(); TasGpu::devalfor(acceleration, num_dimensions, num_x, max_levels, gpu_x, gpu_cachef->num_nodes, gpu_cachef->points, gpu_y, nullptr); } template void GridFourier::evaluateHierarchicalFunctionsInternalGPU(const T gpu_x[], int num_x, GpuVector &wreal, GpuVector &wimag) const{ size_t num_weights = ((size_t) points.getNumIndexes()) * ((size_t) num_x); if (wreal.size() != num_weights) wreal.resize(acceleration, num_weights); if (wimag.size() != num_weights) wimag.resize(acceleration, num_weights); loadGpuNodes(); auto& ccache = getGpuCache(); TasGpu::devalfor(acceleration, num_dimensions, num_x, max_levels, gpu_x, ccache->num_nodes, ccache->points, wreal.data(), wimag.data()); } template void GridFourier::loadGpuNodes() const{ auto& ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (!ccache->num_nodes.empty()) return; std::vector num_nodes(num_dimensions); std::transform(max_levels.begin(), max_levels.end(), num_nodes.begin(), [](int l)->int{ return OneDimensionalMeta::getNumPoints(l, rule_fourier); }); ccache->num_nodes.load(acceleration, num_nodes); const MultiIndexSet &work = (points.empty()) ? needed : points; int num_points = work.getNumIndexes(); Data2D transpoints(work.getNumIndexes(), num_dimensions); for(int i=0; ipoints.load(acceleration, transpoints.begin(), transpoints.end()); } void GridFourier::clearGpuNodes() const{ if (gpu_cache){ gpu_cache->num_nodes.clear(); gpu_cache->points.clear(); } if (gpu_cachef){ gpu_cachef->num_nodes.clear(); gpu_cachef->points.clear(); } } template void GridFourier::loadGpuCoefficients() const{ auto& ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (!ccache->real.empty()) return; int num_points = points.getNumIndexes(); size_t num_coeff = Utils::size_mult(num_outputs, num_points); ccache->real.load(acceleration, num_coeff, fourier_coefs.getStrip(0)); ccache->imag.load(acceleration, num_coeff, fourier_coefs.getStrip(num_points)); } void GridFourier::clearGpuCoefficients() const{ if (gpu_cache){ gpu_cache->real.clear(); gpu_cache->imag.clear(); } if (gpu_cachef){ gpu_cachef->real.clear(); gpu_cachef->imag.clear(); } } void GridFourier::integrate(double q[], double *conformal_correction) const{ if (conformal_correction == 0){ // everything vanishes except the Fourier coeff of e^0 std::copy_n(fourier_coefs.getStrip(0), num_outputs, q); }else{ // Do the expensive computation if we have a conformal map std::fill_n(q, num_outputs, 0.0); std::vector w(getNumPoints()); getQuadratureWeights(w.data()); for(int i=0; i wreal(num_points), wimag(num_points); computeBasis(points, x, wreal.data(), wimag.data()); for(int i=0; i xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(2*num_points, y); #pragma omp parallel for for(int i=0; i(((points.empty()) ? needed : points), xwrap.getStrip(i), ywrap.getStrip(i), 0); } } void GridFourier::evaluateHierarchicalFunctionsInternal(const double x[], int num_x, Data2D &wreal, Data2D &wimag) const{ // when performing internal evaluations, split the matrix into real and complex components // thus only two real gemm() operations can be used (as opposed to one complex gemm) int num_points = getNumPoints(); Utils::Wrapper2D xwrap(num_dimensions, x); wreal = Data2D(num_points, num_x); wimag = Data2D(num_points, num_x); #pragma omp parallel for for(int i=0; i(((points.empty()) ? needed : points), xwrap.getStrip(i), wreal.getStrip(i), wimag.getStrip(i)); } } void GridFourier::setHierarchicalCoefficients(const double c[]){ // takes c to be length 2*num_outputs*num_points // first num_points*num_outputs are the real part; second num_points*num_outputs are the imaginary part clearGpuNodes(); clearGpuCoefficients(); if (points.empty()){ points = std::move(needed); needed = MultiIndexSet(); }else{ clearRefinement(); } auto num_points = points.getNumIndexes(); fourier_coefs = Data2D(num_outputs, 2 * num_points, std::vector(c, c + Utils::size_mult(num_outputs, 2 * num_points))); std::vector x(Utils::size_mult(num_dimensions, num_points)); std::vector y(Utils::size_mult(num_outputs, num_points)); getPoints(x.data()); evaluateBatch(x.data(), points.getNumIndexes(), y.data()); // speed this up later values = StorageSet(num_outputs, num_points, std::move(y)); } void GridFourier::integrateHierarchicalFunctions(double integrals[]) const{ integrals[0] = 1.0; std::fill(integrals + 1, integrals + getNumPoints(), 0.0); } #ifdef Tasmanian_ENABLE_GPU void GridFourier::updateAccelerationData(AccelerationContext::ChangeType change) const{ if (change == AccelerationContext::change_gpu_device){ gpu_cache.reset(); gpu_cachef.reset(); } } #else void GridFourier::updateAccelerationData(AccelerationContext::ChangeType) const{} #endif void GridFourier::estimateAnisotropicCoefficients(TypeDepth type, int output, std::vector &weights) const{ double tol = 1000.0 * Maths::num_tol; int num_points = points.getNumIndexes(); std::vector max_fcoef(num_points); if (output == -1){ // normalize in case of outputs with hugely different scaling std::vector nrm(num_outputs, 0.0); for(int i=0; i &level_limits){ clearRefinement(); std::vector weights; estimateAnisotropicCoefficients(type, output, weights); int level = 0; do{ updateGrid(++level, type, weights, level_limits); }while(getNumNeeded() < min_growth); } void GridFourier::clearRefinement(){ needed = MultiIndexSet(); updated_tensors = MultiIndexSet(); updated_active_tensors = MultiIndexSet(); updated_active_w = std::vector(); } void GridFourier::mergeRefinement(){ if (needed.empty()) return; // nothing to do int num_all_points = getNumLoaded() + getNumNeeded(); values.setValues(std::vector(Utils::size_mult(num_outputs, num_all_points), 0.0)); acceptUpdatedTensors(); } void GridFourier::beginConstruction(){ dynamic_values = Utils::make_unique(num_dimensions, num_outputs); if (points.empty()){ // if we start dynamic construction from an empty grid for(int i=0; iaddTensor(t, [&](int l)->int{ return wrapper.getNumPoints(l); }, weight); } tensors = MultiIndexSet(); active_tensors = MultiIndexSet(); active_w = std::vector(); needed = MultiIndexSet(); values.resize(num_outputs, 0); } } void GridFourier::writeConstructionData(std::ostream &os, bool iomode) const{ if (iomode == mode_ascii) dynamic_values->write(os); else dynamic_values->write(os); } void GridFourier::readConstructionData(std::istream &is, bool iomode){ if (iomode == mode_ascii) dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_ascii_type()); else dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_binary_type()); int max_level = dynamic_values->getMaxTensor(); if (max_level + 1 > wrapper.getNumLevels()) wrapper = OneDimensionalWrapper(max_level, rule_fourier, 0.0, 0.0); dynamic_values->reloadPoints([&](int l)->int{ return wrapper.getNumPoints(l); }); } std::vector GridFourier::getCandidateConstructionPoints(TypeDepth type, int output, const std::vector &level_limits){ std::vector weights; if ((type == type_iptotal) || (type == type_ipcurved) || (type == type_qptotal) || (type == type_qpcurved)){ int min_needed_points = ((type == type_ipcurved) || (type == type_qpcurved)) ? 4 * num_dimensions : 2 * num_dimensions; if (points.getNumIndexes() > min_needed_points) // if there are enough points to estimate coefficients estimateAnisotropicCoefficients(type, output, weights); } return getCandidateConstructionPoints(type, weights, level_limits); } std::vector GridFourier::getCandidateConstructionPoints(TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ MultiIndexManipulations::ProperWeights weights((size_t) num_dimensions, type, anisotropic_weights); // computing the weight for each index requires the cache for the one dimensional indexes // the cache for the one dimensional indexes requires the exactness // exactness can be one of 5 cases based on level/interpolation/quadrature for custom or known rule // the number of required exactness entries is not known until later and we have to be careful not to exceed the levels available for the custom rule // thus, we cache the exactness with a delay std::vector effective_exactness; auto get_exact = [&](int l) -> int{ return effective_exactness[l]; }; auto build_exactness = [&](size_t num) -> void{ effective_exactness.resize(num); if(OneDimensionalMeta::isExactLevel(type)){ for(size_t i=0; i> cache; return getCandidateConstructionPoints([&](int const *t) -> double{ if (cache.empty()){ build_exactness((size_t) wrapper.getNumLevels()); cache = MultiIndexManipulations::generateLevelWeightsCache(weights, get_exact, wrapper.getNumLevels()); } return (double) MultiIndexManipulations::getIndexWeight(t, cache); }, level_limits); }else if (weights.contour == type_curved){ std::vector> cache; return getCandidateConstructionPoints([&](int const *t) -> double{ if (cache.empty()){ build_exactness((size_t) wrapper.getNumLevels()); cache = MultiIndexManipulations::generateLevelWeightsCache(weights, get_exact, wrapper.getNumLevels()); } return MultiIndexManipulations::getIndexWeight(t, cache); }, level_limits); }else{ std::vector> cache; return getCandidateConstructionPoints([&](int const *t) -> double{ if (cache.empty()){ build_exactness((size_t) wrapper.getNumLevels()); cache = MultiIndexManipulations::generateLevelWeightsCache(weights, get_exact, wrapper.getNumLevels()); } return MultiIndexManipulations::getIndexWeight(t, cache); }, level_limits); } } std::vector GridFourier::getCandidateConstructionPoints(std::function getTensorWeight, const std::vector &level_limits){ dynamic_values->clearTesnors(); // clear old tensors MultiIndexSet init_tensors = dynamic_values->getInitialTensors(); // get the initial tensors (created with make grid) MultiIndexSet new_tensors = (level_limits.empty()) ? MultiIndexManipulations::addExclusiveChildren(tensors, init_tensors, level_limits) : MultiIndexManipulations::addExclusiveChildren(tensors, init_tensors, level_limits); if (!new_tensors.empty()){ int max_level = new_tensors.getMaxIndex(); if (max_level+1 > wrapper.getNumLevels()) wrapper = OneDimensionalWrapper(max_level, rule_fourier, 0.0, 0.0); } std::vector tweights(new_tensors.getNumIndexes()); for(int i=0; iaddTensor(new_tensors.getIndex(i), [&](int l)->int{ return wrapper.getNumPoints(l); }, tweights[i]); return MultiIndexManipulations::getIndexesToNodes(dynamic_values->getNodesIndexes(), wrapper); } std::vector GridFourier::getMultiIndex(const double x[]){ std::vector p(num_dimensions); for(int j=0; j Maths::num_tol){ i++; // convert canonical node to index if (i == wrapper.getNumNodes()) wrapper = OneDimensionalWrapper(wrapper.getNumLevels(), rule_fourier, 0.0, 0.0); } p[j] = i; } return p; } void GridFourier::loadConstructedPoint(const double x[], const std::vector &y){ std::vector idx = getMultiIndex(x); auto result = dynamic_values->addNewNode(idx, y); if (result == DynamicConstructorDataGlobal::AddPointResult::tensor_complete){ // if a new tensor is complete loadConstructedTensors(); }else if (result == DynamicConstructorDataGlobal::AddPointResult::tensor_missing){ dynamic_values->addTensor(wrapper.getLevels(idx).data(), [&](int l)->int{ return wrapper.getNumPoints(l); }, dynamic_values->getMaxTensorWeight() + 1.0); } } void GridFourier::loadConstructedPoint(const double x[], int numx, const double y[]){ Utils::Wrapper2D wrapx(num_dimensions, x); Utils::Wrapper2D wrapy(num_outputs, y); for(int i=0; i idx = getMultiIndex(wrapx.getStrip(i)); if (dynamic_values->addNewNode(idx, std::vector(wrapy.getStrip(i), wrapy.getStrip(i) + num_outputs)) == DynamicConstructorDataGlobal::AddPointResult::tensor_missing){ dynamic_values->addTensor(wrapper.getLevels(idx).data(), [&](int l)->int{ return wrapper.getNumPoints(l); }, dynamic_values->getMaxTensorWeight() + 1.0); } } loadConstructedTensors(); } void GridFourier::loadConstructedTensors(){ clearGpuNodes(); clearGpuCoefficients(); MultiIndexSet new_tensors, new_points; StorageSet new_values; dynamic_values->ejectCompleteTensor(tensors, new_tensors, new_points, new_values); if (new_tensors.empty()) return; // nothing to do if (points.empty()){ // no loaded points yet values = std::move(new_values); points = std::move(new_points); }else{ values.addValues(points, new_points, new_values.getValues(0)); points += new_points; } tensors += new_tensors; MultiIndexManipulations::computeActiveTensorsWeights(tensors, active_tensors, active_w); max_levels = MultiIndexManipulations::getMaxIndexes(active_tensors); max_power = MultiIndexManipulations::getMaxIndexes(points); calculateFourierCoefficients(); } void GridFourier::finishConstruction(){ dynamic_values = std::unique_ptr(); } const double* GridFourier::getFourierCoefs() const{ return fourier_coefs.getStrip(0); } } // end TasGrid #endif TASMANIAN-8.1/SparseGrids/tsgGridFourier.hpp000066400000000000000000000266101470551176200206100ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_FOURIER_HPP #define __TASMANIAN_SPARSE_GRID_FOURIER_HPP #include "tsgGridCore.hpp" namespace TasGrid{ #ifndef __TASMANIAN_DOXYGEN_SKIP class GridFourier : public BaseCanonicalGrid { public: GridFourier(AccelerationContext const *acc) : BaseCanonicalGrid(acc){}; friend struct GridReaderVersion5; GridFourier(AccelerationContext const *acc, const GridFourier *fourier, int ibegin, int iend); GridFourier(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits) : BaseCanonicalGrid(acc) { makeGrid(cnum_dimensions, cnum_outputs, depth, type, anisotropic_weights, level_limits); } ~GridFourier() = default; bool isFourier() const override{ return true; } void write(std::ostream &os, bool iomode) const override{ if (iomode == mode_ascii) write(os); else write(os); } template void write(std::ostream &os) const; void makeGrid(int cnum_dimensions, int cnum_outputs, int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits); void updateGrid(int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits); void setTensors(MultiIndexSet &&tset, int cnum_outputs); TypeOneDRule getRule() const override{ return rule_fourier; } void loadNeededValues(const double *vals) override; void getLoadedPoints(double *x) const override; void getNeededPoints(double *x) const override; void getPoints(double *x) const override; // returns the loaded points unless no points are loaded, then returns the needed points void getInterpolationWeights(const double x[], double weights[]) const override; void getQuadratureWeights(double weights[]) const override; void getDifferentiationWeights(const double x[], double weights[]) const override; void evaluate(const double x[], double y[]) const override; void integrate(double q[], double *conformal_correction) const override; void differentiate(const double x[], double jacobian[]) const override; void evaluateBatch(const double x[], int num_x, double y[]) const override; void evaluateBatchGPU(const double gpu_x[], int cpu_num_x, double gpu_y[]) const override; void evaluateBatchGPU(const float gpu_x[], int cpu_num_x, float gpu_y[]) const override; template void evaluateBatchGPUtempl(const T gpu_x[], int cpu_num_x, T gpu_y[]) const; void evaluateHierarchicalFunctionsGPU(const double gpu_x[], int num_x, double gpu_y[]) const override; void evaluateHierarchicalFunctionsGPU(const float gpu_x[], int num_x, float gpu_y[]) const override; template void evaluateHierarchicalFunctionsInternalGPU(const T gpu_x[], int num_x, GpuVector &wreal, GpuVector &wimag) const; void evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const override; void evaluateHierarchicalFunctionsInternal(const double x[], int num_x, Data2D &wreal, Data2D &wimag) const; void setHierarchicalCoefficients(const double c[]) override; void integrateHierarchicalFunctions(double integrals[]) const override; void updateAccelerationData(AccelerationContext::ChangeType change) const override; void estimateAnisotropicCoefficients(TypeDepth type, int output, std::vector &weights) const; void setAnisotropicRefinement(TypeDepth type, int min_growth, int output, const std::vector &level_limits); void clearRefinement() override; void mergeRefinement() override; void beginConstruction() override; void writeConstructionData(std::ostream &os, bool) const override; void readConstructionData(std::istream &is, bool) override; std::vector getCandidateConstructionPoints(TypeDepth type, const std::vector &weights, const std::vector &level_limits); std::vector getCandidateConstructionPoints(TypeDepth type, int output, const std::vector &level_limits); std::vector getCandidateConstructionPoints(std::function getTensorWeight, const std::vector &level_limits); void loadConstructedPoint(const double x[], const std::vector &y) override; void loadConstructedPoint(const double x[], int numx, const double y[]) override; void finishConstruction() override; const double* getFourierCoefs() const; protected: void calculateFourierCoefficients(); MultiIndexSet selectTensors(size_t dims, int depth, TypeDepth type, const std::vector &anisotropic_weights, std::vector const &level_limits) const; void proposeUpdatedTensors(); void acceptUpdatedTensors(); std::vector> generateIndexingMap() const; void loadConstructedTensors(); std::vector getMultiIndex(const double x[]); template void computeBasis(const MultiIndexSet &work, const T x[], T wreal[], T wimag[]) const{ int num_points = work.getNumIndexes(); std::vector>> cache(num_dimensions); for(int j=0; j(1.0, 0.0); T theta = -2.0 * Maths::pi * x[j]; std::complex step(std::cos(theta), std::sin(theta)); std::complex pw(1.0, 0.0); for(int i=1; i(pw); } } for(int i=0; i v(1.0, 0.0); for(int j=0; j active_w; MultiIndexSet updated_tensors; MultiIndexSet updated_active_tensors; std::vector updated_active_w; std::vector max_levels; Data2D fourier_coefs; std::vector max_power; std::unique_ptr dynamic_values; template void loadGpuNodes() const; template void loadGpuCoefficients() const; inline std::unique_ptr>& getGpuCacheOverload(double) const{ return gpu_cache; } inline std::unique_ptr>& getGpuCacheOverload(float) const{ return gpu_cachef; } template inline std::unique_ptr>& getGpuCache() const{ return getGpuCacheOverload(static_cast(0.0)); } mutable std::unique_ptr> gpu_cache; mutable std::unique_ptr> gpu_cachef; }; // Old version reader template<> struct GridReaderVersion5{ template static std::unique_ptr read(AccelerationContext const *acc, std::istream &is){ std::unique_ptr grid = Utils::make_unique(acc); grid->num_dimensions = IO::readNumber(is); grid->num_outputs = IO::readNumber(is); grid->tensors = MultiIndexSet(is, iomode()); grid->active_tensors = MultiIndexSet(is, iomode()); grid->active_w = IO::readVector(is, grid->active_tensors.getNumIndexes()); if (IO::readFlag(is)) grid->points = MultiIndexSet(is, iomode()); if (IO::readFlag(is)) grid->needed = MultiIndexSet(is, iomode()); grid->max_levels = IO::readVector(is, grid->num_dimensions); if (grid->num_outputs > 0){ grid->values = StorageSet(is, iomode()); if (IO::readFlag(is)) grid->fourier_coefs = IO::readData2D(is, grid->num_outputs, 2 * grid->points.getNumIndexes()); } int oned_max_level; if (IO::readFlag(is)){ grid->updated_tensors = MultiIndexSet(is, iomode()); oned_max_level = grid->updated_tensors.getMaxIndex(); grid->updated_active_tensors = MultiIndexSet(is, iomode()); grid->updated_active_w = IO::readVector(is, grid->updated_active_tensors.getNumIndexes()); }else{ oned_max_level = *std::max_element(grid->max_levels.begin(), grid->max_levels.end()); } grid->wrapper = OneDimensionalWrapper(oned_max_level, rule_fourier, 0.0, 0.0); grid->max_power = MultiIndexManipulations::getMaxIndexes(((grid->points.empty()) ? grid->needed : grid->points)); return grid; } }; #endif // __TASMANIAN_DOXYGEN_SKIP } #endif TASMANIAN-8.1/SparseGrids/tsgGridGlobal.cpp000066400000000000000000001211151470551176200203640ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_GLOBAL_CPP #define __TASMANIAN_SPARSE_GRID_GLOBAL_CPP #include "tsgGridGlobal.hpp" #include "tsgTPLWrappers.hpp" namespace TasGrid{ template void GridGlobal::write(std::ostream &os) const{ if (iomode == mode_ascii){ os << std::scientific; os.precision(17); } IO::writeNumbers(os, num_dimensions, num_outputs); IO::writeNumbers(os, alpha, beta); IO::writeRule(rule, os); if (rule == rule_customtabulated) custom.write(os); tensors.write(os); active_tensors.write(os); if (!active_w.empty()) IO::writeVector(active_w, os); IO::writeFlag(!points.empty(), os); if (!points.empty()) points.write(os); IO::writeFlag(!needed.empty(), os); if (!needed.empty()) needed.write(os); IO::writeVector(max_levels, os); if (num_outputs > 0) values.write(os); IO::writeFlag(!updated_tensors.empty(), os); if (!updated_tensors.empty()){ updated_tensors.write(os); updated_active_tensors.write(os); IO::writeVector(updated_active_w, os); } } template void GridGlobal::write(std::ostream &) const; template void GridGlobal::write(std::ostream &) const; void GridGlobal::clearRefinement(){ needed = MultiIndexSet(); updated_tensors = MultiIndexSet(); updated_active_tensors = MultiIndexSet(); updated_active_w = std::vector(); } MultiIndexSet GridGlobal::selectTensors(size_t dims, int depth, TypeDepth type, const std::vector &anisotropic_weights, TypeOneDRule crule, std::vector const &level_limits) const{ if (OneDimensionalMeta::isExactLevel(type)){ // no need to know exactness return MultiIndexManipulations::selectTensors(dims, depth, type, [&](int l) -> int{ return l; }, anisotropic_weights, level_limits); }else{ // work with exactness specific to the rule if (crule == rule_customtabulated){ if (OneDimensionalMeta::isExactQuadrature(type)){ return MultiIndexManipulations::selectTensors(dims, depth, type, [&](int l) -> int{ return custom.getQExact(l); }, anisotropic_weights, level_limits); }else{ return MultiIndexManipulations::selectTensors(dims, depth, type, [&](int l) -> int{ return custom.getIExact(l); }, anisotropic_weights, level_limits); } }else{ // using regular OneDimensionalMeta if (OneDimensionalMeta::isExactQuadrature(type)){ return MultiIndexManipulations::selectTensors(dims, depth, type, [&](int l) -> int{ return OneDimensionalMeta::getQExact(l, crule); }, anisotropic_weights, level_limits); }else{ return MultiIndexManipulations::selectTensors(dims, depth, type, [&](int l) -> int{ return OneDimensionalMeta::getIExact(l, crule); }, anisotropic_weights, level_limits); } } } } void GridGlobal::recomputeTensorRefs(const MultiIndexSet &work){ int nz_weights = active_tensors.getNumIndexes(); tensor_refs.resize((size_t) nz_weights); if (OneDimensionalMeta::isNonNested(rule)){ #pragma omp parallel for schedule(dynamic) for(int i=0; i(active_tensors.getIndex(i), wrapper, work); }else{ #pragma omp parallel for schedule(dynamic) for(int i=0; i(active_tensors.getIndex(i), wrapper, work); } } void GridGlobal::makeGrid(int cnum_dimensions, int cnum_outputs, int depth, TypeDepth type, TypeOneDRule crule, const std::vector &anisotropic_weights, double calpha, double cbeta, const char* custom_filename, const std::vector &level_limits){ if (crule == rule_customtabulated){ custom.read(custom_filename); } setTensors(selectTensors((size_t) cnum_dimensions, depth, type, anisotropic_weights, crule, level_limits), cnum_outputs, crule, calpha, cbeta); } GridGlobal::GridGlobal(AccelerationContext const *acc, GridGlobal const *global, int ibegin, int iend) : BaseCanonicalGrid(acc, *global, ibegin, iend), rule(global->rule), alpha(global->alpha), beta(global->beta), wrapper(global->wrapper), tensors(global->tensors), active_tensors(global->active_tensors), active_w(global->active_w), tensor_refs(global->tensor_refs), max_levels(global->max_levels), updated_tensors(global->updated_tensors), updated_active_tensors(global->updated_active_tensors), updated_active_w(global->updated_active_w), custom((global->rule == rule_customtabulated) ? global->custom : CustomTabulated()){ if (global->dynamic_values){ dynamic_values = Utils::make_unique(*global->dynamic_values); if (num_outputs != global->num_outputs) dynamic_values->restrictData(ibegin, iend); } } void GridGlobal::setTensors(MultiIndexSet &&tset, int cnum_outputs, TypeOneDRule crule, double calpha, double cbeta){ clearGpuNodes(); clearGpuValues(); tensor_refs = std::vector>(); points = MultiIndexSet(); values = StorageSet(); updated_tensors = MultiIndexSet(); updated_active_tensors = MultiIndexSet(); updated_active_w = std::vector(); tensors = std::move(tset); num_dimensions = (int) tensors.getNumDimensions(); num_outputs = cnum_outputs; rule = crule; alpha = calpha; beta = cbeta; max_levels = MultiIndexManipulations::getMaxIndexes(tensors); wrapper = OneDimensionalWrapper(custom, *std::max_element(max_levels.begin(), max_levels.end()), rule, alpha, beta); MultiIndexManipulations::computeActiveTensorsWeights(tensors, active_tensors, active_w); needed = (OneDimensionalMeta::isNonNested(rule)) ? MultiIndexManipulations::generateNonNestedPoints(active_tensors, wrapper) : MultiIndexManipulations::generateNestedPoints(tensors, [&](int l) -> int{ return wrapper.getNumPoints(l); }); recomputeTensorRefs(needed); if (num_outputs == 0){ points = std::move(needed); needed = MultiIndexSet(); }else{ values.resize(num_outputs, needed.getNumIndexes()); } } void GridGlobal::proposeUpdatedTensors(){ wrapper = OneDimensionalWrapper(custom, updated_tensors.getMaxIndex(), rule, alpha, beta); MultiIndexManipulations::computeActiveTensorsWeights(updated_tensors, updated_active_tensors, updated_active_w); // the new needed points are the points associated with the updated_active_tensors without the existing set of loaded points needed = ((OneDimensionalMeta::isNonNested(rule)) ? MultiIndexManipulations::generateNonNestedPoints(updated_active_tensors, wrapper) : MultiIndexManipulations::generateNestedPoints(updated_tensors, [&](int l) -> int{ return wrapper.getNumPoints(l); })) - points; } void GridGlobal::updateGrid(int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ if ((num_outputs == 0) || points.empty()){ makeGrid(num_dimensions, num_outputs, depth, type, rule, anisotropic_weights, alpha, beta, 0, level_limits); }else{ clearRefinement(); updated_tensors = selectTensors((size_t) num_dimensions, depth, type, anisotropic_weights, rule, level_limits); if (!(updated_tensors - tensors).empty()){ updated_tensors += tensors; proposeUpdatedTensors(); } } } void GridGlobal::getLoadedPoints(double *x) const{ MultiIndexManipulations::indexesToNodes(points, wrapper, x); } void GridGlobal::getNeededPoints(double *x) const{ MultiIndexManipulations::indexesToNodes(needed, wrapper, x); } void GridGlobal::getPoints(double *x) const{ if (points.empty()){ getNeededPoints(x); }else{ getLoadedPoints(x); }; } void GridGlobal::getQuadratureWeights(double weights[]) const{ std::fill_n(weights, (points.empty()) ? needed.getNumIndexes() : points.getNumIndexes(), 0.0); std::vector num_oned_points(num_dimensions); for(int n=0; n=0; j--){ w *= wrapper.getWeight(levels[j], t % num_oned_points[j]); t /= num_oned_points[j]; } weights[tensor_refs[n][i]] += tensor_weight * w; } } } void GridGlobal::getInterpolationWeights(const double x[], double weights[]) const{ std::fill_n(weights, (points.empty()) ? needed.getNumIndexes() : points.getNumIndexes(), 0.0); CacheLagrange lcache(num_dimensions, max_levels, wrapper, x); std::vector num_oned_points(num_dimensions); for(int n=0; n=0; j--){ w *= lcache.getLagrange(j, levels[j], t % num_oned_points[j]); t /= num_oned_points[j]; } weights[tensor_refs[n][i]] += tensor_weight * w; } } } void GridGlobal::getDifferentiationWeights(const double x[], double weights[]) const{ // The weight of the i-th point in the k-th dimension is given by weights[i * num_dimensions + k]. std::fill_n(weights, (points.empty() ? needed.getNumIndexes(): points.getNumIndexes()) * num_dimensions, 0.0); CacheLagrange lcache(num_dimensions, max_levels, wrapper, x); CacheLagrangeDerivative ldcache(num_dimensions, max_levels, wrapper, x); std::vector diff_values(num_dimensions); std::vector num_oned_points(num_dimensions); for(int n=0; n=0; k--){ basis_value = lcache.getLagrange(k, levels[k], t % num_oned_points[k]); for(int j=0; j=0; j--) weights[tensor_refs[n][i] * num_dimensions + j] += tensor_weight * diff_values[j]; } } } void GridGlobal::acceptUpdatedTensors(){ if (points.empty()){ points = std::move(needed); needed = MultiIndexSet(); }else if (!needed.empty()){ clearGpuNodes(); points += needed; needed = MultiIndexSet(); tensors = std::move(updated_tensors); updated_tensors = MultiIndexSet(); active_tensors = std::move(updated_active_tensors); updated_active_tensors = MultiIndexSet(); active_w = std::move(updated_active_w); updated_active_w = std::vector(); max_levels = MultiIndexManipulations::getMaxIndexes(tensors); recomputeTensorRefs(points); } } void GridGlobal::loadNeededValues(const double *vals){ clearGpuValues(); if (points.empty() || needed.empty()){ values.setValues(vals); }else{ values.addValues(points, needed, vals); } acceptUpdatedTensors(); } void GridGlobal::mergeRefinement(){ if (needed.empty()) return; // nothing to do clearGpuValues(); int num_all_points = getNumLoaded() + getNumNeeded(); values.setValues(std::vector(Utils::size_mult(num_outputs, num_all_points), 0.0)); acceptUpdatedTensors(); } void GridGlobal::beginConstruction(){ dynamic_values = Utils::make_unique(num_dimensions, num_outputs); if (points.empty()){ // if we start dynamic construction from an empty grid for(int i=0; iaddTensor(t, [&](int l)->int{ return wrapper.getNumPoints(l); }, weight); } tensors = MultiIndexSet(); active_tensors = MultiIndexSet(); active_w = std::vector(); needed = MultiIndexSet(); values.resize(num_outputs, 0); } } void GridGlobal::writeConstructionData(std::ostream &os, bool iomode) const{ if (iomode == mode_ascii) dynamic_values->write(os); else dynamic_values->write(os); } void GridGlobal::readConstructionData(std::istream &is, bool iomode){ if (iomode == mode_ascii) dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_ascii_type()); else dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_binary_type()); int max_level = dynamic_values->getMaxTensor(); if (max_level + 1 > wrapper.getNumLevels()) wrapper = OneDimensionalWrapper(custom, max_level, rule, alpha, beta); dynamic_values->reloadPoints([&](int l)->int{ return wrapper.getNumPoints(l); }); } std::vector GridGlobal::getCandidateConstructionPoints(TypeDepth type, int output, const std::vector &level_limits){ std::vector weights; if ((type == type_iptotal) || (type == type_ipcurved) || (type == type_qptotal) || (type == type_qpcurved)){ int min_needed_points = ((type == type_ipcurved) || (type == type_qpcurved)) ? 4 * num_dimensions : 2 * num_dimensions; if (points.getNumIndexes() > min_needed_points) // if there are enough points to estimate coefficients estimateAnisotropicCoefficients(type, output, weights); } return getCandidateConstructionPoints(type, weights, level_limits); } std::vector GridGlobal::getCandidateConstructionPoints(TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ MultiIndexManipulations::ProperWeights weights((size_t) num_dimensions, type, anisotropic_weights); // computing the weight for each index requires the cache for the one dimensional indexes // the cache for the one dimensional indexes requires the exactness // exactness can be one of 5 cases based on level/interpolation/quadrature for custom or known rule // the number of required exactness entries is not known until later and we have to be careful not to exceed the levels available for the custom rule // thus, we cache the exactness with a delay std::vector effective_exactness; auto get_exact = [&](int l) -> int{ return effective_exactness[l]; }; auto build_exactness = [&](size_t num) -> void{ effective_exactness.resize(num); if(OneDimensionalMeta::isExactLevel(type)){ for(size_t i=0; i> cache; return getCandidateConstructionPoints([&](int const *t) -> double{ if (cache.empty()){ build_exactness((size_t) wrapper.getNumLevels()); cache = MultiIndexManipulations::generateLevelWeightsCache(weights, get_exact, wrapper.getNumLevels()); } return (double) MultiIndexManipulations::getIndexWeight(t, cache); }, level_limits); }else if (weights.contour == type_curved){ std::vector> cache; return getCandidateConstructionPoints([&](int const *t) -> double{ if (cache.empty()){ build_exactness((size_t) wrapper.getNumLevels()); cache = MultiIndexManipulations::generateLevelWeightsCache(weights, get_exact, wrapper.getNumLevels()); } return MultiIndexManipulations::getIndexWeight(t, cache); }, level_limits); }else{ std::vector> cache; return getCandidateConstructionPoints([&](int const *t) -> double{ if (cache.empty()){ build_exactness((size_t) wrapper.getNumLevels()); cache = MultiIndexManipulations::generateLevelWeightsCache(weights, get_exact, wrapper.getNumLevels()); } return MultiIndexManipulations::getIndexWeight(t, cache); }, level_limits); } } std::vector GridGlobal::getCandidateConstructionPoints(std::function getTensorWeight, const std::vector &level_limits){ dynamic_values->clearTesnors(); // clear old tensors MultiIndexSet init_tensors = dynamic_values->getInitialTensors(); // get the initial tensors (created with make grid) MultiIndexSet new_tensors = (level_limits.empty()) ? MultiIndexManipulations::addExclusiveChildren(tensors, init_tensors, level_limits) : MultiIndexManipulations::addExclusiveChildren(tensors, init_tensors, level_limits); if (!new_tensors.empty()){ auto max_indexes = MultiIndexManipulations::getMaxIndexes(new_tensors); int max_level = *std::max_element(max_indexes.begin(), max_indexes.end()); if (max_level+1 > wrapper.getNumLevels()) wrapper = OneDimensionalWrapper(custom, max_level, rule, alpha, beta); } std::vector tweights(new_tensors.getNumIndexes()); for(int i=0; iaddTensor(new_tensors.getIndex(i), [&](int l)->int{ return wrapper.getNumPoints(l); }, tweights[i]); return MultiIndexManipulations::getIndexesToNodes(dynamic_values->getNodesIndexes(), wrapper); } std::vector GridGlobal::getMultiIndex(const double x[]){ std::vector p(num_dimensions); for(int j=0; j Maths::num_tol){ i++; // convert canonical node to index if (i == wrapper.getNumNodes()) wrapper = OneDimensionalWrapper(custom, wrapper.getNumLevels(), wrapper.getRule(), alpha, beta); } p[j] = i; } return p; } void GridGlobal::loadConstructedPoint(const double x[], const std::vector &y){ std::vector idx = getMultiIndex(x); auto result = dynamic_values->addNewNode(idx, y); if (result == DynamicConstructorDataGlobal::AddPointResult::tensor_complete){ // if a new tensor is complete loadConstructedTensors(); }else if (result == DynamicConstructorDataGlobal::AddPointResult::tensor_missing){ dynamic_values->addTensor(wrapper.getLevels(idx).data(), [&](int l)->int{ return wrapper.getNumPoints(l); }, dynamic_values->getMaxTensorWeight() + 1.0); } } void GridGlobal::loadConstructedPoint(const double x[], int numx, const double y[]){ Utils::Wrapper2D wrapx(num_dimensions, x); Utils::Wrapper2D wrapy(num_outputs, y); for(int i=0; i idx = getMultiIndex(wrapx.getStrip(i)); if (dynamic_values->addNewNode(idx, std::vector(wrapy.getStrip(i), wrapy.getStrip(i) + num_outputs)) == DynamicConstructorDataGlobal::AddPointResult::tensor_missing){ dynamic_values->addTensor(wrapper.getLevels(idx).data(), [&](int l)->int{ return wrapper.getNumPoints(l); }, dynamic_values->getMaxTensorWeight() + 1.0); } } loadConstructedTensors(); } void GridGlobal::loadConstructedTensors(){ MultiIndexSet new_tensors, new_points; StorageSet new_values; dynamic_values->ejectCompleteTensor(tensors, new_tensors, new_points, new_values); if (new_tensors.empty()) return; // nothing to do clearGpuNodes(); clearGpuValues(); if (points.empty()){ // no loaded points yet values = std::move(new_values); points = std::move(new_points); }else{ values.addValues(points, new_points, new_values.getValues(0)); points += new_points; } tensors += new_tensors; MultiIndexManipulations::computeActiveTensorsWeights(tensors, active_tensors, active_w); max_levels = MultiIndexManipulations::getMaxIndexes(active_tensors); recomputeTensorRefs(points); } void GridGlobal::finishConstruction(){ dynamic_values = std::unique_ptr(); } void GridGlobal::evaluate(const double x[], double y[]) const{ std::vector w(points.getNumIndexes()); getInterpolationWeights(x, w.data()); std::fill_n(y, num_outputs, 0.0); for(int i=0; imode){ case accel_gpu_magma: case accel_gpu_cuda: { acceleration->setDevice(); GpuVector gpu_x(acceleration, num_dimensions, num_x, x), gpu_result(acceleration, num_x, num_outputs); evaluateBatchGPU(gpu_x.data(), num_x, gpu_result.data()); gpu_result.unload(acceleration, y); break; } case accel_gpu_cublas: { acceleration->setDevice(); loadGpuValues(); int num_points = points.getNumIndexes(); Data2D weights(num_points, num_x); evaluateHierarchicalFunctions(x, num_x, weights.getStrip(0)); TasGpu::denseMultiplyMixed(acceleration, num_outputs, num_x, num_points, 1.0, gpu_cache->values, weights.data(), 0.0, y); break; } case accel_cpu_blas: { int num_points = points.getNumIndexes(); Data2D weights(num_points, num_x); if (num_x > 1) evaluateHierarchicalFunctions(x, num_x, weights.getStrip(0)); else // skips small OpenMP overhead getInterpolationWeights(x, weights.getStrip(0)); TasBLAS::denseMultiply(num_outputs, num_x, num_points, 1.0, values.getValues(0), weights.getStrip(0), 0.0, y); break; } default: { Utils::Wrapper2D xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(num_outputs, y); #pragma omp parallel for for(int i=0; i void GridGlobal::evaluateBatchGPUtempl(T const gpu_x[], int cpu_num_x, T gpu_y[]) const{ loadGpuValues(); int num_points = points.getNumIndexes(); GpuVector gpu_basis(acceleration, cpu_num_x, num_points); evaluateHierarchicalFunctionsGPU(gpu_x, cpu_num_x, gpu_basis.data()); TasGpu::denseMultiply(acceleration, num_outputs, cpu_num_x, num_points, 1.0, getGpuCache()->values, gpu_basis, 0.0, gpu_y); } void GridGlobal::evaluateBatchGPU(const double *gpu_x, int cpu_num_x, double gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridGlobal::evaluateBatchGPU(const float gpu_x[], int cpu_num_x, float gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } template void GridGlobal::evaluateHierarchicalFunctionsGPUtempl(T const gpu_x[], int cpu_num_x, T *gpu_y) const{ auto& ccache = getGpuCache(); loadGpuNodes(); TasGpu::devalglo(acceleration, !OneDimensionalMeta::isNonNested(rule), (rule == rule_clenshawcurtis0), num_dimensions, cpu_num_x, getNumPoints(), ccache->num_basis, gpu_x, ccache->nodes, ccache->coeff, ccache->tensor_weights, ccache->nodes_per_level, ccache->offset_per_level, ccache->map_dimension, ccache->map_level, ccache->active_tensors, ccache->active_num_points, ccache->dim_offsets, ccache->map_tensor, ccache->map_index, ccache->map_reference, gpu_y); } void GridGlobal::evaluateHierarchicalFunctionsGPU(const double gpu_x[], int cpu_num_x, double *gpu_y) const{ evaluateHierarchicalFunctionsGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridGlobal::evaluateHierarchicalFunctionsGPU(const float gpu_x[], int cpu_num_x, float *gpu_y) const{ evaluateHierarchicalFunctionsGPUtempl(gpu_x, cpu_num_x, gpu_y); } template void GridGlobal::loadGpuValues() const{ auto& ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (ccache->values.empty()) ccache->values.load(acceleration, values.begin(), values.end()); } void GridGlobal::clearGpuValues() const{ if (gpu_cache) gpu_cache->values.clear(); } template void GridGlobal::loadGpuNodes() const{ auto& ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (!ccache->nodes.empty()) return; // already loaded // data for stage 1 (Lagrange caching) ccache->nodes.load(acceleration, (OneDimensionalMeta::isNonNested(rule)) ? wrapper.getAllNodes() : wrapper.getUnique()); ccache->coeff.load(acceleration, wrapper.getAllCoeff()); ccache->nodes_per_level.load(acceleration, wrapper.getNumNodesPerLevel()); ccache->offset_per_level.load(acceleration, wrapper.getOffsetNodesPerLevel()); std::vector map_dims, map_level, dim_offsets; int num_basis = 0; for(int dim=0; dimnum_basis = num_basis; ccache->map_dimension.load(acceleration, map_dims); ccache->map_level.load(acceleration, map_level); std::vector tweights(active_w.size()); std::transform(active_w.begin(), active_w.end(), tweights.begin(), [](int i)->double{ return static_cast(i); }); ccache->tensor_weights.load(acceleration, tweights); ccache->active_tensors.load(acceleration, active_tensors.begin(), active_tensors.end()); std::vector active_num_points(active_tensors.totalSize()); std::transform(active_tensors.begin(), active_tensors.end(), active_num_points.begin(), [&](int i)->int{ return wrapper.getNumPoints(i); }); ccache->active_num_points.load(acceleration, active_num_points); ccache->dim_offsets.load(acceleration, dim_offsets); std::vector map_tensor, map_index, map_reference; auto inump = active_num_points.begin(); for(int n=0; nmap_tensor.load(acceleration, map_tensor); ccache->map_index.load(acceleration, map_index); ccache->map_reference.load(acceleration, map_reference); } void GridGlobal::clearGpuNodes() const{ if (gpu_cache) gpu_cache->clearNodes(); if (gpu_cachef) gpu_cachef->clearNodes(); } void GridGlobal::integrate(double q[], double *conformal_correction) const{ std::vector w(getNumPoints()); getQuadratureWeights(w.data()); if (conformal_correction != 0) for(int i=0; i w(points.getNumIndexes() * num_dimensions); getDifferentiationWeights(x, w.data()); std::fill_n(jacobian, num_outputs * num_dimensions, 0.0); for(int i=0; i xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(num_points, y); #pragma omp parallel for for(int i=0; i GridGlobal::computeSurpluses(int output, bool normalize) const{ int num_points = points.getNumIndexes(); std::vector surp((size_t) num_points); if (OneDimensionalMeta::isSequence(rule)){ double max_surp = 0.0; for(int i=0; i max_surp) max_surp = std::abs(surp[i]); } GridSequence seq(acceleration, MultiIndexSet(points), 1, rule); // there is an extra copy here, but the sequence grid does the surplus computation automatically seq.loadNeededValues(surp.data()); std::copy_n(seq.getSurpluses(), surp.size(), surp.data()); if (normalize) for(auto &s : surp) s /= max_surp; }else{ MultiIndexSet polynomial_set = getPolynomialSpaceSet(true); MultiIndexSet quadrature_tensors = MultiIndexManipulations::generateLowerMultiIndexSet((size_t) num_dimensions, [&](const std::vector &index) -> bool{ std::vector qindex = index; for(auto &i : qindex) i = (i > 0) ? 1 + OneDimensionalMeta::getQExact(i - 1, rule_gausspatterson) : 0; return !polynomial_set.missing(qindex); }); GridGlobal QuadGrid(acceleration); if (quadrature_tensors.getMaxIndex() < TableGaussPatterson::getNumLevels()-1){ QuadGrid.setTensors(std::move(quadrature_tensors), 0, rule_gausspatterson, 0.0, 0.0); }else{ quadrature_tensors = MultiIndexManipulations::generateLowerMultiIndexSet((size_t) num_dimensions, [&](const std::vector &index) -> bool{ std::vector qindex = index; for(auto &i : qindex) i = (i > 0) ? 1 + OneDimensionalMeta::getQExact(i - 1, rule_clenshawcurtis) : 0; return polynomial_set.missing(qindex); }); QuadGrid.setTensors(std::move(quadrature_tensors), 0, rule_clenshawcurtis, 0.0, 0.0); } size_t qn = (size_t) QuadGrid.getNumPoints(); std::vector w(qn); QuadGrid.getQuadratureWeights(w.data()); std::vector x(qn * ((size_t) num_dimensions)); std::vector y(qn * ((size_t) num_outputs)); QuadGrid.getPoints(x.data()); std::vector I(qn); evaluateBatch(x.data(), (int) qn, y.data()); auto iter_y = y.begin(); std::advance(iter_y, output); for(auto &ii : I){ ii = *iter_y; std::advance(iter_y, num_outputs); } #pragma omp parallel for schedule(dynamic) for(int i=0; i &weights) const{ double tol = 1000.0 * Maths::num_tol; std::vector surp = computeSurpluses(output, false); weights = MultiIndexManipulations::inferAnisotropicWeights(acceleration, rule, type, points, surp, tol); } void GridGlobal::setAnisotropicRefinement(TypeDepth type, int min_growth, int output, const std::vector &level_limits){ clearRefinement(); std::vector weights; estimateAnisotropicCoefficients(type, output, weights); int level = 0; do{ updateGrid(++level, type, weights, level_limits); }while(getNumNeeded() < min_growth); } void GridGlobal::setSurplusRefinement(double tolerance, int output, const std::vector &level_limits){ clearRefinement(); std::vector surp = computeSurpluses(output, true); int n = points.getNumIndexes(); std::vector flagged(n); for(int i=0; i tolerance); MultiIndexSet kids = MultiIndexManipulations::selectFlaggedChildren(points, flagged, level_limits); if (!kids.empty()){ kids += points; MultiIndexManipulations::completeSetToLower(kids); updated_tensors = std::move(kids); proposeUpdatedTensors(); } } void GridGlobal::setHierarchicalCoefficients(const double c[]){ clearGpuValues(); if (!points.empty()) clearRefinement(); loadNeededValues(c); } void GridGlobal::integrateHierarchicalFunctions(double integrals[]) const{ getQuadratureWeights(integrals); } double GridGlobal::legendre(int n, double x){ if (n == 0) return 1.0; if (n == 1) return x; double lm = 1, l = x; for(int i=2; i<=n; i++){ double lp = ((2*i - 1) * x * l) / ((double) i) - ((i - 1) * lm) / ((double) i); lm = l; l = lp; } return l; } #ifdef Tasmanian_ENABLE_GPU void GridGlobal::updateAccelerationData(AccelerationContext::ChangeType change) const{ if (change == AccelerationContext::change_gpu_device){ gpu_cache.reset(); gpu_cachef.reset(); } } #else void GridGlobal::updateAccelerationData(AccelerationContext::ChangeType) const{} #endif MultiIndexSet GridGlobal::getPolynomialSpaceSet(bool interpolation) const{ if (interpolation){ if (rule == rule_customtabulated){ return MultiIndexManipulations::createPolynomialSpace(active_tensors, [&](int l)-> int{ return custom.getIExact(l); }); }else{ return MultiIndexManipulations::createPolynomialSpace(active_tensors, [&](int l)-> int{ return OneDimensionalMeta::getIExact(l, rule); }); } }else{ if (rule == rule_customtabulated){ return MultiIndexManipulations::createPolynomialSpace(active_tensors, [&](int l)-> int{ return custom.getQExact(l); }); }else{ return MultiIndexManipulations::createPolynomialSpace(active_tensors, [&](int l)-> int{ return OneDimensionalMeta::getQExact(l, rule); }); } } } std::vector GridGlobal::getPolynomialSpace(bool interpolation) const{ return getPolynomialSpaceSet(interpolation).release(); } } #endif TASMANIAN-8.1/SparseGrids/tsgGridGlobal.hpp000066400000000000000000000267731470551176200204070ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_GLOBAL_HPP #define __TASMANIAN_SPARSE_GRID_GLOBAL_HPP #include "tsgGridSequence.hpp" #include "tsgCacheLagrange.hpp" namespace TasGrid{ #ifndef __TASMANIAN_DOXYGEN_SKIP class GridGlobal : public BaseCanonicalGrid{ public: GridGlobal(AccelerationContext const *acc) : BaseCanonicalGrid(acc), rule(rule_none), alpha(0.0), beta(0.0){} friend struct GridReaderVersion5; GridGlobal(AccelerationContext const *acc, const GridGlobal *global, int ibegin, int iend); GridGlobal(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int depth, TypeDepth type, TypeOneDRule crule, const std::vector &anisotropic_weights, double calpha, double cbeta, const char* custom_filename, const std::vector &level_limits) : BaseCanonicalGrid(acc){ makeGrid(cnum_dimensions, cnum_outputs, depth, type, crule, anisotropic_weights, calpha, cbeta, custom_filename, level_limits); } GridGlobal(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int depth, TypeDepth type, CustomTabulated &&crule, const std::vector &anisotropic_weights, const std::vector &level_limits) : BaseCanonicalGrid(acc), custom(std::move(crule)) { setTensors(selectTensors((size_t) cnum_dimensions, depth, type, anisotropic_weights, rule_customtabulated, level_limits), cnum_outputs, rule_customtabulated, 0.0, 0.0); } bool isGlobal() const override{ return true; } void write(std::ostream &os, bool iomode) const override{ if (iomode == mode_ascii) write(os); else write(os); } template void write(std::ostream &os) const; void makeGrid(int cnum_dimensions, int cnum_outputs, int depth, TypeDepth type, TypeOneDRule crule, const std::vector &anisotropic_weights, double calpha, double cbeta, const char* custom_filename, const std::vector &level_limits); void setTensors(MultiIndexSet &&tset, int cnum_outputs, TypeOneDRule crule, double calpha, double cbeta); void updateGrid(int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits); TypeOneDRule getRule() const override{ return rule; } const char* getCustomRuleDescription() const{ return (custom.getNumLevels() > 0) ? custom.getDescription() : ""; } double getAlpha() const{ return alpha; } double getBeta() const{ return beta; } void getLoadedPoints(double *x) const override; void getNeededPoints(double *x) const override; void getPoints(double *x) const override; // returns the loaded points unless no points are loaded, then returns the needed points void getQuadratureWeights(double weights[]) const override; void getInterpolationWeights(const double x[], double weights[]) const override; void getDifferentiationWeights(const double x[], double weights[]) const override; void loadNeededValues(const double *vals) override; void evaluate(const double x[], double y[]) const override; void integrate(double q[], double *conformal_correction) const override; void differentiate(const double x[], double jacobian[]) const override; void evaluateBatch(const double x[], int num_x, double y[]) const override; void evaluateBatchGPU(const double[], int, double[]) const override; void evaluateBatchGPU(const float[], int, float[]) const override; template void evaluateBatchGPUtempl(T const[], int, T *) const; void evaluateHierarchicalFunctionsGPU(const double[], int, double *) const override; void evaluateHierarchicalFunctionsGPU(const float[], int, float *) const override; template void evaluateHierarchicalFunctionsGPUtempl(T const[], int, T *) const; void estimateAnisotropicCoefficients(TypeDepth type, int output, std::vector &weights) const; void setAnisotropicRefinement(TypeDepth type, int min_growth, int output, const std::vector &level_limits); void setSurplusRefinement(double tolerance, int output, const std::vector &level_limits); void clearRefinement() override; void mergeRefinement() override; void beginConstruction() override; void writeConstructionData(std::ostream &os, bool) const override; void readConstructionData(std::istream &is, bool) override; std::vector getCandidateConstructionPoints(TypeDepth type, const std::vector &weights, const std::vector &level_limits); std::vector getCandidateConstructionPoints(TypeDepth type, int output, const std::vector &level_limits); std::vector getCandidateConstructionPoints(std::function getTensorWeight, const std::vector &level_limits); void loadConstructedPoint(const double x[], const std::vector &y) override; void loadConstructedPoint(const double x[], int numx, const double y[]) override; void finishConstruction() override; void evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const override; void setHierarchicalCoefficients(const double c[]) override; void integrateHierarchicalFunctions(double integrals[]) const override; void updateAccelerationData(AccelerationContext::ChangeType change) const override; std::vector getPolynomialSpace(bool interpolation) const; protected: std::vector computeSurpluses(int output, bool normalize) const; // only for sequence rules, select the output to compute the surpluses static double legendre(int n, double x); // assumes that if rule == rule_customtabulated, then custom is already loaded MultiIndexSet selectTensors(size_t dims, int depth, TypeDepth type, const std::vector &anisotropic_weights, TypeOneDRule rule, std::vector const &level_limits) const; void recomputeTensorRefs(const MultiIndexSet &work); void proposeUpdatedTensors(); void acceptUpdatedTensors(); MultiIndexSet getPolynomialSpaceSet(bool interpolation) const; void loadConstructedTensors(); std::vector getMultiIndex(const double x[]); void clearGpuValues() const; void clearGpuNodes() const; private: TypeOneDRule rule; double alpha, beta; OneDimensionalWrapper wrapper; MultiIndexSet tensors; MultiIndexSet active_tensors; std::vector active_w; std::vector> tensor_refs; std::vector max_levels; // for evaluation purposes, counts the maximum level in each direction (only counts tensors) MultiIndexSet updated_tensors; MultiIndexSet updated_active_tensors; std::vector updated_active_w; CustomTabulated custom; std::unique_ptr dynamic_values; template void loadGpuNodes() const; template void loadGpuValues() const; inline std::unique_ptr>& getGpuCacheOverload(double) const{ return gpu_cache; } inline std::unique_ptr>& getGpuCacheOverload(float) const{ return gpu_cachef; } template inline std::unique_ptr>& getGpuCache() const{ return getGpuCacheOverload(static_cast(0.0)); } mutable std::unique_ptr> gpu_cache; mutable std::unique_ptr> gpu_cachef; }; // Old version reader template<> struct GridReaderVersion5{ template static std::unique_ptr read(AccelerationContext const *acc, std::istream &is){ std::unique_ptr grid = Utils::make_unique(acc); grid->num_dimensions = IO::readNumber(is); grid->num_outputs = IO::readNumber(is); grid->alpha = IO::readNumber(is); grid->beta = IO::readNumber(is); grid->rule = IO::readRule(is); if (grid->rule == rule_customtabulated) grid->custom = CustomTabulated(is, iomode()); grid->tensors = MultiIndexSet(is, iomode()); grid->active_tensors = MultiIndexSet(is, iomode()); grid->active_w = IO::readVector(is, grid->active_tensors.getNumIndexes()); if (IO::readFlag(is)) grid->points = MultiIndexSet(is, iomode()); if (IO::readFlag(is)) grid->needed = MultiIndexSet(is, iomode()); grid->max_levels = IO::readVector(is, grid->num_dimensions); if (grid->num_outputs > 0) grid->values = StorageSet(is, iomode()); int oned_max_level; if (IO::readFlag(is)){ grid->updated_tensors = MultiIndexSet(is, iomode()); oned_max_level = grid->updated_tensors.getMaxIndex(); grid->updated_active_tensors = MultiIndexSet(is, iomode()); grid->updated_active_w = IO::readVector(is, grid->updated_active_tensors.getNumIndexes()); }else{ oned_max_level = *std::max_element(grid->max_levels.begin(), grid->max_levels.end()); } grid->wrapper = OneDimensionalWrapper(grid->custom, oned_max_level, grid->rule, grid->alpha, grid->beta); grid->recomputeTensorRefs((grid->points.empty()) ? grid->needed : grid->points); return grid; } }; #endif // __TASMANIAN_DOXYGEN_SKIP } #endif TASMANIAN-8.1/SparseGrids/tsgGridLocalPolynomial.cpp000066400000000000000000002633251470551176200222740ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_LPOLY_CPP #define __TASMANIAN_SPARSE_GRID_LPOLY_CPP #include "tsgGridLocalPolynomial.hpp" #include "tsgTPLWrappers.hpp" namespace TasGrid{ template void GridLocalPolynomial::write(std::ostream &os) const{ if (iomode == mode_ascii){ os << std::scientific; os.precision(17); } IO::writeNumbers(os, num_dimensions, num_outputs, order, top_level); IO::writeRule(RuleLocal::getRule(effective_rule), os); IO::writeFlag(!points.empty(), os); if (!points.empty()) points.write(os); if (iomode == mode_ascii){ // backwards compatible: surpluses and needed, or needed and surpluses IO::writeFlag((surpluses.getNumStrips() != 0), os); if (!surpluses.empty()) surpluses.writeVector(os); IO::writeFlag(!needed.empty(), os); if (!needed.empty()) needed.write(os); }else{ IO::writeFlag(!needed.empty(), os); if (!needed.empty()) needed.write(os); IO::writeFlag((surpluses.getNumStrips() != 0), os); if (!surpluses.empty()) surpluses.writeVector(os); } IO::writeFlag((parents.getNumStrips() != 0), os); if (!parents.empty()) parents.writeVector(os); IO::writeNumbers(os, static_cast(roots.size())); if (roots.size() > 0){ // the tree is empty, can happend when using dynamic construction IO::writeVector(roots, os); IO::writeVector(pntr, os); IO::writeVector(indx, os); } if (num_outputs > 0) values.write(os); } template void GridLocalPolynomial::write(std::ostream &) const; template void GridLocalPolynomial::write(std::ostream &) const; GridLocalPolynomial::GridLocalPolynomial(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int depth, int corder, TypeOneDRule crule, const std::vector &level_limits) : BaseCanonicalGrid(acc, cnum_dimensions, cnum_outputs, MultiIndexSet(), MultiIndexSet(), StorageSet()), order(corder), effective_rule(RuleLocal::getEffectiveRule(order, (crule == rule_semilocalp and order < 2) ? rule_localp : crule)) { MultiIndexSet tensors = MultiIndexManipulations::selectTensors((size_t) num_dimensions, depth, type_level, [&](int i) -> int{ return i; }, std::vector(), level_limits); switch(effective_rule) { case RuleLocal::erule::pwc: needed = MultiIndexManipulations::generateNestedPoints(tensors, [&](int l) -> int{ return RuleLocal::getNumPoints(l); }); break; case RuleLocal::erule::localp: needed = MultiIndexManipulations::generateNestedPoints(tensors, [&](int l) -> int{ return RuleLocal::getNumPoints(l); }); break; case RuleLocal::erule::semilocalp: needed = MultiIndexManipulations::generateNestedPoints(tensors, [&](int l) -> int{ return RuleLocal::getNumPoints(l); }); break; case RuleLocal::erule::localp0: needed = MultiIndexManipulations::generateNestedPoints(tensors, [&](int l) -> int{ return RuleLocal::getNumPoints(l); }); break; default: // case RuleLocal::erule::localpb: needed = MultiIndexManipulations::generateNestedPoints(tensors, [&](int l) -> int{ return RuleLocal::getNumPoints(l); }); break; }; buildTree(); if (num_outputs == 0){ points = std::move(needed); needed = MultiIndexSet(); parents = HierarchyManipulations::computeDAGup(points, effective_rule); }else{ values.resize(num_outputs, needed.getNumIndexes()); } } GridLocalPolynomial::GridLocalPolynomial(AccelerationContext const *acc, GridLocalPolynomial const *pwpoly, int ibegin, int iend) : BaseCanonicalGrid(acc, *pwpoly, ibegin, iend), order(pwpoly->order), top_level(pwpoly->top_level), surpluses((num_outputs == pwpoly->num_outputs) ? pwpoly->surpluses : pwpoly->surpluses.splitData(ibegin, iend)), parents(pwpoly->parents), roots(pwpoly->roots), pntr(pwpoly->pntr), indx(pwpoly->indx), effective_rule(pwpoly->effective_rule){ if (pwpoly->dynamic_values){ dynamic_values = Utils::make_unique(*pwpoly->dynamic_values); if (num_outputs != pwpoly->num_outputs) dynamic_values->restrictData(ibegin, iend); } } GridLocalPolynomial::GridLocalPolynomial(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int corder, TypeOneDRule crule, std::vector &&pnts, std::vector &&vals, std::vector &&surps) : BaseCanonicalGrid(acc, cnum_dimensions, cnum_outputs, MultiIndexSet(cnum_dimensions, std::move(pnts)), MultiIndexSet(), StorageSet(cnum_outputs, static_cast(vals.size() / cnum_outputs), std::move(vals))), order(corder), surpluses(Data2D(cnum_outputs, points.getNumIndexes(), std::move(surps))), effective_rule(RuleLocal::getEffectiveRule(order, crule)){ buildTree(); } struct localp_loaded{}; struct localp_needed{}; template void GridLocalPolynomial::getPoints(double *x) const { int num_points = (std::is_same::value) ? points.getNumIndexes() : needed.getNumIndexes(); Utils::Wrapper2D split(num_dimensions, x); #pragma omp parallel for schedule(static) for(int i=0; i::value) ? points.getIndex(i) : needed.getIndex(i); double *s = split.getStrip(i); for(int j=0; j(p[j]); } } void GridLocalPolynomial::getLoadedPoints(double *x) const{ using pmode = localp_loaded; switch(effective_rule) { case RuleLocal::erule::pwc: getPoints(x); break; case RuleLocal::erule::localp: getPoints(x); break; case RuleLocal::erule::semilocalp: getPoints(x); break; case RuleLocal::erule::localp0: getPoints(x); break; default: // case RuleLocal::erule::localpb: getPoints(x); break; }; } void GridLocalPolynomial::getNeededPoints(double *x) const{ using pmode = localp_needed; switch(effective_rule) { case RuleLocal::erule::pwc: getPoints(x); break; case RuleLocal::erule::localp: getPoints(x); break; case RuleLocal::erule::semilocalp: getPoints(x); break; case RuleLocal::erule::localp0: getPoints(x); break; default: // case RuleLocal::erule::localpb: getPoints(x); break; }; } void GridLocalPolynomial::getPoints(double *x) const{ if (points.empty()){ getNeededPoints(x); }else{ getLoadedPoints(x); } } void GridLocalPolynomial::evaluate(const double x[], double y[]) const{ std::fill_n(y, num_outputs, 0.0); std::vector sindx; // dummy variables, never references in mode 0 below std::vector svals; walkTree<0>(points, x, sindx, svals, y); } void GridLocalPolynomial::evaluateBatchOpenMP(const double x[], int num_x, double y[]) const{ if (num_x == 1){ evaluate(x, y); return; } Utils::Wrapper2D xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(num_outputs, y); #pragma omp parallel for for(int i=0; imode){ case accel_gpu_magma: case accel_gpu_cuda: { acceleration->setDevice(); if ((order == -1) || (order > 2) || (num_x == 1)){ // GPU evaluations are available only for order 0, 1, and 2. Cubic will come later, but higher order will not be supported. // cannot use GPU to accelerate the evaluation of a single vector evaluateGpuMixed(x, num_x, y); return; } GpuVector gpu_x(acceleration, num_dimensions, num_x, x), gpu_result(acceleration, num_x, num_outputs); evaluateBatchGPU(gpu_x.data(), num_x, gpu_result.data()); gpu_result.unload(acceleration, y); break; } case accel_gpu_cublas: { acceleration->setDevice(); evaluateGpuMixed(x, num_x, y); break; } case accel_cpu_blas: { if (acceleration->algorithm_select == AccelerationContext::algorithm_sparse or (acceleration->algorithm_select == AccelerationContext::algorithm_autoselect and num_outputs <= 1024)){ evaluateBatchOpenMP(x, num_x, y); return; } std::vector sindx, spntr; std::vector svals; buildSpareBasisMatrix(x, num_x, 32, spntr, sindx, svals); // build sparse matrix corresponding to x int num_points = points.getNumIndexes(); double nnz = (double) spntr[num_x]; double total_size = ((double) num_x) * ((double) num_points); if ((acceleration->algorithm_select == AccelerationContext::algorithm_dense) or ((acceleration->algorithm_select == AccelerationContext::algorithm_autoselect) and (nnz / total_size > 0.1))){ // potentially wastes a lot of memory Data2D A(num_points, num_x, 0.0); for(int i=0; i ywrap(num_outputs, y); #pragma omp parallel for for(int i=0; i levels = HierarchyManipulations::computeLevels(points, effective_rule); std::vector> lpnts = HierarchyManipulations::splitByLevels(points, levels); std::vector> lvals = HierarchyManipulations::splitByLevels(values, levels); Data2D allx(num_dimensions, points.getNumIndexes()); getPoints(allx.data()); std::vector> lx = HierarchyManipulations::splitByLevels(allx, levels); MultiIndexSet cumulative_poitns((size_t) num_dimensions, lpnts[0].release()); StorageSet cumulative_surpluses = StorageSet(num_outputs, cumulative_poitns.getNumIndexes(), lvals[0].release()); for(size_t l = 1; l < lpnts.size(); l++){ // loop over the levels // note that level_points.getNumIndexes() == lx[l].getNumStrips() == lvals[l].getNumStrips() MultiIndexSet level_points(num_dimensions, lpnts[l].release()); GridLocalPolynomial upper_grid(acceleration, num_dimensions, num_outputs, order, getRule(), std::vector(cumulative_poitns.begin(), cumulative_poitns.end()), // copy cumulative_poitns std::vector(Utils::size_mult(num_outputs, cumulative_poitns.getNumIndexes())), // dummy values, will not be read or used std::vector(cumulative_surpluses.begin(), cumulative_surpluses.end())); // copy the cumulative_surpluses Data2D upper_evaluate(num_outputs, level_points.getNumIndexes()); int batch_size = 20000; // needs tuning if (acceleration->algorithm_select == AccelerationContext::algorithm_dense){ // dense uses lots of memory, try to keep it contained to about 4GB batch_size = 536870912 / upper_grid.getNumPoints() - 2 * (num_outputs + num_dimensions); if (batch_size < 100) batch_size = 100; // use at least 100 points } for(int i=0; i(num_outputs, points.getNumIndexes(), cumulative_surpluses.release()); } void GridLocalPolynomial::evaluateGpuMixed(const double x[], int num_x, double y[]) const{ loadGpuSurpluses(); std::vector sindx, spntr; std::vector svals; if (num_x > 1){ buildSpareBasisMatrix(x, num_x, 32, spntr, sindx, svals); }else{ walkTree<2>(points, x, sindx, svals, nullptr); #ifdef Tasmanian_ENABLE_DPCPP // CUDA and HIP have methods for sparse-vector times dense matrix or vector // therefore, CUDA/HIP do not use spntr when num_x is equal to 1, but DPC++ needs to set it too spntr = {0, static_cast(sindx.size())}; #endif } TasGpu::sparseMultiplyMixed(acceleration, num_outputs, num_x, points.getNumIndexes(), 1.0, gpu_cache->surpluses, spntr, sindx, svals, y); } template void GridLocalPolynomial::evaluateBatchGPUtempl(const T gpu_x[], int cpu_num_x, T gpu_y[]) const{ if ((order == -1) || (order > 2)) throw std::runtime_error("ERROR: GPU evaluations are availabe only for local polynomial grid with order 0, 1, and 2"); loadGpuSurpluses(); int num_points = points.getNumIndexes(); if (acceleration->algorithm_select == AccelerationContext::algorithm_dense){ GpuVector gpu_basis(acceleration, cpu_num_x, num_points); evaluateHierarchicalFunctionsGPU(gpu_x, cpu_num_x, gpu_basis.data()); TasGpu::denseMultiply(acceleration, num_outputs, cpu_num_x, num_points, 1.0, getGpuCache()->surpluses, gpu_basis, 0.0, gpu_y); }else{ GpuVector gpu_spntr, gpu_sindx; GpuVector gpu_svals; buildSparseBasisMatrixGPU(gpu_x, cpu_num_x, gpu_spntr, gpu_sindx, gpu_svals); TasGpu::sparseMultiply(acceleration, num_outputs, cpu_num_x, num_points, 1.0, getGpuCache()->surpluses, gpu_spntr, gpu_sindx, gpu_svals, gpu_y); } } void GridLocalPolynomial::evaluateBatchGPU(const double gpu_x[], int cpu_num_x, double gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridLocalPolynomial::evaluateBatchGPU(const float gpu_x[], int cpu_num_x, float gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridLocalPolynomial::evaluateHierarchicalFunctionsGPU(const double gpu_x[], int cpu_num_x, double *gpu_y) const{ loadGpuBasis(); TasGpu::devalpwpoly(acceleration, order, RuleLocal::getRule(effective_rule), num_dimensions, cpu_num_x, getNumPoints(), gpu_x, gpu_cache->nodes.data(), gpu_cache->support.data(), gpu_y); } void GridLocalPolynomial::buildSparseBasisMatrixGPU(const double gpu_x[], int cpu_num_x, GpuVector &gpu_spntr, GpuVector &gpu_sindx, GpuVector &gpu_svals) const{ loadGpuBasis(); loadGpuHierarchy(); TasGpu::devalpwpoly_sparse(acceleration, order, RuleLocal::getRule(effective_rule), num_dimensions, cpu_num_x, gpu_x, gpu_cache->nodes, gpu_cache->support, gpu_cache->hpntr, gpu_cache->hindx, gpu_cache->hroots, gpu_spntr, gpu_sindx, gpu_svals); } void GridLocalPolynomial::evaluateHierarchicalFunctionsGPU(const float gpu_x[], int cpu_num_x, float *gpu_y) const{ loadGpuBasis(); TasGpu::devalpwpoly(acceleration, order, RuleLocal::getRule(effective_rule), num_dimensions, cpu_num_x, getNumPoints(), gpu_x, gpu_cachef->nodes.data(), gpu_cachef->support.data(), gpu_y); } void GridLocalPolynomial::buildSparseBasisMatrixGPU(const float gpu_x[], int cpu_num_x, GpuVector &gpu_spntr, GpuVector &gpu_sindx, GpuVector &gpu_svals) const{ loadGpuBasis(); loadGpuHierarchy(); TasGpu::devalpwpoly_sparse(acceleration, order, RuleLocal::getRule(effective_rule), num_dimensions, cpu_num_x, gpu_x, gpu_cachef->nodes, gpu_cachef->support, gpu_cachef->hpntr, gpu_cachef->hindx, gpu_cachef->hroots, gpu_spntr, gpu_sindx, gpu_svals); } template void GridLocalPolynomial::loadGpuBasis() const{ auto& ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (!ccache->nodes.empty()) return; Data2D cpu_nodes(num_dimensions, getNumPoints()); getPoints(cpu_nodes.getStrip(0)); ccache->nodes.load(acceleration, cpu_nodes.begin(), cpu_nodes.end()); Data2D cpu_support = [&](void)->Data2D{ const MultiIndexSet &work = (points.empty()) ? needed : points; switch(effective_rule) { case RuleLocal::erule::pwc: return encodeSupportForGPU<0, rule_localp, T>(work); case RuleLocal::erule::localp: return (order == 1) ? encodeSupportForGPU<1, rule_localp, T>(work) : encodeSupportForGPU<2, rule_localp, T>(work); case RuleLocal::erule::semilocalp: return (order == 1) ? encodeSupportForGPU<1, rule_semilocalp, T>(work) : encodeSupportForGPU<2, rule_semilocalp, T>(work); case RuleLocal::erule::localp0: return (order == 1) ? encodeSupportForGPU<1, rule_localp0, T>(work) : encodeSupportForGPU<2, rule_localp0, T>(work); default: // case RuleLocal::erule::localpb: return (order == 1) ? encodeSupportForGPU<1, rule_localpb, T>(work) : encodeSupportForGPU<2, rule_localpb, T>(work); }; }(); ccache->support.load(acceleration, cpu_support.begin(), cpu_support.end()); } void GridLocalPolynomial::clearGpuBasisHierarchy(){ if (gpu_cache) gpu_cache->clearBasisHierarchy(); if (gpu_cachef) gpu_cachef->clearBasisHierarchy(); } template void GridLocalPolynomial::loadGpuHierarchy() const{ auto& ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (!ccache->hpntr.empty()) return; ccache->hpntr.load(acceleration, pntr); ccache->hindx.load(acceleration, indx); ccache->hroots.load(acceleration, roots); } template void GridLocalPolynomial::loadGpuSurpluses() const{ auto& ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (ccache->surpluses.size() != 0) return; ccache->surpluses.load(acceleration, surpluses.begin(), surpluses.end()); } void GridLocalPolynomial::clearGpuSurpluses(){ if (gpu_cache) gpu_cache->surpluses.clear(); if (gpu_cachef) gpu_cachef->surpluses.clear(); } void GridLocalPolynomial::updateValues(double const *vals){ clearGpuSurpluses(); if (needed.empty()){ values.setValues(vals); }else{ clearGpuBasisHierarchy(); if (points.empty()){ // initial grid, just relabel needed as points (loaded) values.setValues(vals); points = std::move(needed); needed = MultiIndexSet(); }else{ // merge needed and points values.addValues(points, needed, vals); points += needed; needed = MultiIndexSet(); buildTree(); } } } void GridLocalPolynomial::loadNeededValues(const double *vals){ #ifdef Tasmanian_ENABLE_GPU if (acceleration->on_gpu()){ acceleration->setDevice(); loadNeededValuesGPU(vals); return; } #endif updateValues(vals); recomputeSurpluses(); } void GridLocalPolynomial::mergeRefinement(){ if (needed.empty()) return; // nothing to do clearGpuSurpluses(); int num_all_points = getNumLoaded() + getNumNeeded(); values.setValues(std::vector(Utils::size_mult(num_all_points, num_outputs), 0.0)); if (points.empty()){ points = std::move(needed); needed = MultiIndexSet(); }else{ points += needed; needed = MultiIndexSet(); buildTree(); } surpluses = Data2D(num_outputs, num_all_points); } void GridLocalPolynomial::beginConstruction(){ dynamic_values = Utils::make_unique(); if (points.empty()){ dynamic_values->initial_points = std::move(needed); needed = MultiIndexSet(); roots.clear(); pntr.clear(); indx.clear(); } } void GridLocalPolynomial::writeConstructionData(std::ostream &os, bool iomode) const{ if (iomode == mode_ascii) dynamic_values->write(os); else dynamic_values->write(os); } void GridLocalPolynomial::readConstructionData(std::istream &is, bool iomode){ if (iomode == mode_ascii) dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_ascii_type()); else dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_binary_type()); } template std::vector GridLocalPolynomial::getCandidateConstructionPoints(double tolerance, TypeRefinement criteria, int output, std::vector const &level_limits, double const *scale_correction){ // combine the initial points with negative weights and the refinement candidates with surplus weights (no need to normalize, the sort uses relative values) MultiIndexSet refine_candidates = getRefinementCanidates(tolerance, criteria, output, level_limits, scale_correction); MultiIndexSet new_points = (dynamic_values->initial_points.empty()) ? std::move(refine_candidates) : refine_candidates - dynamic_values->initial_points; // compute the weights for the new_points points std::vector norm = getNormalization(); int active_outputs = (output == -1) ? num_outputs : 1; Utils::Wrapper2D scale(active_outputs, scale_correction); std::vector default_scale; if (scale_correction == nullptr){ // if no scale provided, assume default 1.0 default_scale = std::vector(Utils::size_mult(active_outputs, points.getNumIndexes()), 1.0); scale = Utils::Wrapper2D(active_outputs, default_scale.data()); } auto getDominantSurplus = [&](int i)-> double{ double dominant = 0.0; const double *s = surpluses.getStrip(i); const double *c = scale.getStrip(i); if (output == -1){ for(int k=0; k refine_weights(new_points.getNumIndexes()); #pragma omp parallel for for(int i=0; i p = new_points.copyIndex(i); HierarchyManipulations::touchAllImmediateRelatives(p, points, [&](int relative)->void{ weight = std::max(weight, getDominantSurplus(relative)); }); refine_weights[i] = weight; // those will be inverted } // if using stable refinement, ensure the weight of the parents is never less than the children if (!new_points.empty() && ((criteria == refine_parents_first) || (criteria == refine_fds))){ auto rlevels = HierarchyManipulations::computeLevels(new_points); auto split = HierarchyManipulations::splitByLevels(new_points, rlevels); for(auto is = split.rbegin(); is != split.rend(); is++){ for(int i=0; igetNumStrips(); i++){ std::vector parent(is->getStrip(i), is->getStrip(i) + num_dimensions); double correction = refine_weights[new_points.getSlot(parent)]; // will never be missing for(auto &p : parent){ int r = p; p = RuleLocal::getParent(r); int ip = (p == -1) ? -1 : new_points.getSlot(parent); // if parent is among the refined if (ip != -1) refine_weights[ip] += correction; p = RuleLocal::getStepParent(r); ip = (p == -1) ? -1 : new_points.getSlot(parent); // if parent is among the refined if (ip != -1) refine_weights[ip] += correction; p = r; } } } }else if (!new_points.empty() && (criteria == refine_stable)){ // stable refinement, ensure that if level[i] < level[j] then weight[i] > weight[j] auto rlevels = HierarchyManipulations::computeLevels(new_points); auto split = HierarchyManipulations::splitByLevels(new_points, rlevels); double max_weight = 0.0; for(auto is = split.rbegin(); is != split.rend(); is++){ // loop backwards in levels double correction = max_weight; for(int i=0; igetNumStrips(); i++){ int idx = new_points.getSlot(std::vector(is->getStrip(i), is->getStrip(i) + num_dimensions)); refine_weights[idx] += correction; max_weight = std::max(max_weight, refine_weights[idx]); } } } // compute the weights for the initial points std::vector initial_levels = HierarchyManipulations::computeLevels(dynamic_values->initial_points); std::forward_list weighted_points; for(int i=0; iinitial_points.getNumIndexes(); i++) weighted_points.push_front({dynamic_values->initial_points.copyIndex(i), {-1.0 / ((double) initial_levels[i])}}); for(int i=0; ibool{ return (a.value[0] < b.value[0]); }); return listToLocalNodes(weighted_points, num_dimensions, [&](int i)->double{ return RuleLocal::getNode(i); }); } std::vector GridLocalPolynomial::getCandidateConstructionPoints(double tolerance, TypeRefinement criteria, int output, std::vector const &level_limits, double const *scale_correction) { switch(effective_rule) { case RuleLocal::erule::pwc: return getCandidateConstructionPoints(tolerance, criteria, output, level_limits, scale_correction); case RuleLocal::erule::localp: return getCandidateConstructionPoints(tolerance, criteria, output, level_limits, scale_correction); case RuleLocal::erule::semilocalp: return getCandidateConstructionPoints(tolerance, criteria, output, level_limits, scale_correction); case RuleLocal::erule::localp0: return getCandidateConstructionPoints(tolerance, criteria, output, level_limits, scale_correction); default: // case RuleLocal::erule::localpb: return getCandidateConstructionPoints(tolerance, criteria, output, level_limits, scale_correction); }; } template std::vector GridLocalPolynomial::getMultiIndex(const double x[]){ std::vector p(num_dimensions); // convert x to p, maybe expensive for(int j=0; j(i) - x[j]) > Maths::num_tol) i++; p[j] = i; } return p; } template void GridLocalPolynomial::loadConstructedPoint(const double x[], const std::vector &y){ auto p = getMultiIndex(x); dynamic_values->initial_points.removeIndex(p); bool isConnected = false; HierarchyManipulations::touchAllImmediateRelatives(p, points, [&](int)->void{ isConnected = true; }); int lvl = RuleLocal::getLevel(p[0]); for(int j=1; j(p[j]); if (isConnected || (lvl == 0)){ expandGrid(p, y); loadConstructedPoints(); }else{ dynamic_values->data.push_front({p, y}); } } void GridLocalPolynomial::loadConstructedPoint(const double x[], const std::vector &y){ switch(effective_rule) { case RuleLocal::erule::pwc: return loadConstructedPoint(x, y); case RuleLocal::erule::localp: return loadConstructedPoint(x, y); case RuleLocal::erule::semilocalp: return loadConstructedPoint(x, y); case RuleLocal::erule::localp0: return loadConstructedPoint(x, y); default: // case RuleLocal::erule::localpb: return loadConstructedPoint(x, y); }; } template void GridLocalPolynomial::expandGrid(const std::vector &point, const std::vector &value){ if (points.empty()){ // only one point points = MultiIndexSet((size_t) num_dimensions, std::vector(point)); values = StorageSet(num_outputs, 1, std::vector(value)); surpluses = Data2D(num_outputs, 1, std::vector(value)); // one value is its own surplus }else{ // merge with existing points // compute the surplus for the point std::vector xnode(num_dimensions); for(int j=0; j(point[j]); std::vector approximation(num_outputs), surp(num_outputs); evaluate(xnode.data(), approximation.data()); std::transform(approximation.begin(), approximation.end(), value.begin(), surp.begin(), [&](double e, double v)->double{ return v - e; }); std::vector graph = getSubGraph(point); // get the descendant nodes that must be updated later values.addValues(points, MultiIndexSet(num_dimensions, std::vector(point)), value.data()); // added the value points.addSortedIndexes(point); // add the point int newindex = points.getSlot(point); surpluses.appendStrip(newindex, surp); // find the index of the new point for(auto &g : graph) if (g >= newindex) g++; // all points belowe the newindex have been shifted down by one spot std::vector levels(points.getNumIndexes(), 0); // compute the levels, but only for the new indexes for(auto &g : graph){ int const *pnt = points.getIndex(g); int l = RuleLocal::getLevel(pnt[0]); for(int j=1; j(pnt[j]); levels[g] = l; std::copy_n(values.getValues(g), num_outputs, surpluses.getStrip(g)); // reset the surpluses to the values (will be updated) } // compute the current DAG and update the surplused for the descendants updateSurpluses(points, top_level + 1, levels, HierarchyManipulations::computeDAGup(points)); } buildTree(); // the tree is needed for evaluate(), must be rebuild every time the points set is updated } template void GridLocalPolynomial::loadConstructedPoint(const double x[], int numx, const double y[]){ Utils::Wrapper2D wrapx(num_dimensions, x); std::vector> pnts(numx); #pragma omp parallel for for(int i=0; i(wrapx.getStrip(i)); if (!dynamic_values->initial_points.empty()){ Data2D combined_pnts(num_dimensions, numx); for(int i=0; iinitial_points = dynamic_values->initial_points - combined_pnts; } Utils::Wrapper2D wrapy(num_outputs, y); for(int i=0; idata.push_front({std::move(pnts[i]), std::vector(wrapy.getStrip(i), wrapy.getStrip(i) + num_outputs)}); loadConstructedPoints(); } void GridLocalPolynomial::loadConstructedPoint(const double x[], int numx, const double y[]){ switch(effective_rule) { case RuleLocal::erule::pwc: return loadConstructedPoint(x, numx, y); case RuleLocal::erule::localp: return loadConstructedPoint(x, numx, y); case RuleLocal::erule::semilocalp: return loadConstructedPoint(x, numx, y); case RuleLocal::erule::localp0: return loadConstructedPoint(x, numx, y); default: // case RuleLocal::erule::localpb: return loadConstructedPoint(x, numx, y); }; } template void GridLocalPolynomial::loadConstructedPoints(){ Data2D candidates(num_dimensions, (int) std::distance(dynamic_values->data.begin(), dynamic_values->data.end())); for(struct{ int i; std::forward_list::iterator d; } p = {0, dynamic_values->data.begin()}; p.d != dynamic_values->data.end(); p.i++, p.d++){ std::copy_n(p.d->point.begin(), num_dimensions, candidates.getIStrip(p.i)); } auto new_points = HierarchyManipulations::getLargestConnected(points, MultiIndexSet(candidates)); if (new_points.empty()) return; clearGpuBasisHierarchy(); // the points will change, clear the cache clearGpuSurpluses(); auto vals = dynamic_values->extractValues(new_points); if (points.empty()){ points = std::move(new_points); values.setValues(std::move(vals)); }else{ values.addValues(points, new_points, vals.data()); points += new_points; } buildTree(); recomputeSurpluses(); // costly, but the only option under the circumstances } void GridLocalPolynomial::finishConstruction(){ dynamic_values.reset(); } template std::vector GridLocalPolynomial::getSubGraph(std::vector const &point) const{ std::vector graph, p = point; std::vector used(points.getNumIndexes(), false); int max_1d_kids = RuleLocal::getMaxNumKids(); int max_kids = max_1d_kids * num_dimensions; std::vector monkey_count(1, 0), monkey_tail; while(monkey_count[0] < max_kids){ if (monkey_count.back() < max_kids){ int dim = monkey_count.back() / max_1d_kids; monkey_tail.push_back(p[dim]); p[dim] = RuleLocal::getKid(monkey_tail.back(), monkey_count.back() % max_1d_kids); int slot = points.getSlot(p); if ((slot == -1) || used[slot]){ // this kid is missing p[dim] = monkey_tail.back(); monkey_tail.pop_back(); monkey_count.back()++; }else{ // found kid, go deeper in the graph graph.push_back(slot); used[slot] = true; monkey_count.push_back(0); } }else{ monkey_count.pop_back(); int dim = monkey_count.back() / max_1d_kids; p[dim] = monkey_tail.back(); monkey_tail.pop_back(); monkey_count.back()++; } } return graph; } void GridLocalPolynomial::getInterpolationWeights(const double x[], double weights[]) const{ const MultiIndexSet &work = (points.empty()) ? needed : points; std::vector active_points; std::vector hbasis_values; std::fill_n(weights, work.getNumIndexes(), 0.0); // construct a sparse vector and apply transpose surplus transformation walkTree<1>(work, x, active_points, hbasis_values, nullptr); auto ibasis = hbasis_values.begin(); for(auto i : active_points) weights[i] = *ibasis++; applyTransformationTransposed<0>(weights, work, active_points); } void GridLocalPolynomial::getDifferentiationWeights(const double x[], double weights[]) const { // Based on GridLocalPolynomial::getInterpolationWeights(). const MultiIndexSet &work = (points.empty()) ? needed : points; std::vector active_points; std::vector diff_hbasis_values; std::fill_n(weights, work.getNumIndexes(), 0.0); walkTree<4>(work, x, active_points, diff_hbasis_values, nullptr); auto ibasis = diff_hbasis_values.begin(); for(auto i : active_points) for (int d=0; d(weights, work, active_points); } void GridLocalPolynomial::evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const{ const MultiIndexSet &work = (points.empty()) ? needed : points; int num_points = work.getNumIndexes(); Utils::Wrapper2D xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(num_points, y); switch(effective_rule) { case RuleLocal::erule::pwc: #pragma omp parallel for for(int i=0; i(work.getIndex(j), this_x, dummy); } break; case RuleLocal::erule::localp: #pragma omp parallel for for(int i=0; i(work.getIndex(j), this_x, dummy); } break; case RuleLocal::erule::semilocalp: #pragma omp parallel for for(int i=0; i(work.getIndex(j), this_x, dummy); } break; case RuleLocal::erule::localp0: #pragma omp parallel for for(int i=0; i(work.getIndex(j), this_x, dummy); } break; default: // case RuleLocal::erule::localpb: #pragma omp parallel for for(int i=0; i(work.getIndex(j), this_x, dummy); } break; }; } template void GridLocalPolynomial::recomputeSurpluses() { surpluses = Data2D(num_outputs, points.getNumIndexes(), std::vector(values.begin(), values.end())); // There are two available algorithms here: // - global sparse Kronecker (kron), implemented here in recomputeSurpluses() // - sparse matrix in matrix-free form (mat), implemented in updateSurpluses() // // (kron) has the additional restriction that it will only work when the hierarchy is complete // i.e., all point (multi-indexes) have all of their parents // this is guaranteed for a full-tensor grid, non-adaptive grid, or a grid adapted with the stable refinement strategy // other refinement strategies or using dynamic refinement (even with a stable refinement strategy) // may yield a hierarchy-complete grid, but this is not mathematically guaranteed // // computing the dagUp allows us to check (at runtime) if the grid is_complete, and exclude (kron) if incomplete // the completeness check can be done on the fly but it does incur cost // // approximate computational cost, let n be the number of points and d be the number of dimensions // (kron) d n n^(1/d) due to standard Kronecker reasons, except it is hard to find the "effective" n due to sparsity // (mat) d^2 n log(n) since there are d log(n) ancestors and basis functions are product of d one dimensional functions // naturally, there are constants and those also depend on the system, e.g., number of threads, thread scheduling, cache ... // (mat) has a more even load per thread and parallelizes better // // for d = 1, the algorithms are the same, except (kron) explicitly forms the matrix and the matrix free (mat) version is much better // for d = 2, the (mat) algorithm is still faster // for d = 3, and sufficiently large size the (mat) algorithm still wins // the breaking point depends on n, the order and system // for d = 4 and above, the (kron) algorithm is much faster // it is possible that for sufficiently large n (mat) will win again // but tested on 12 cores CPUs (Intel and AMD) up to n = 3.5 million, the (kron) method is over 2x faster // higher dimensions will favor (kron) even more if (num_dimensions <= 2 or (num_dimensions == 3 and points.getNumIndexes() > 2000000)) { Data2D dagUp = HierarchyManipulations::computeDAGup(points); std::vector level = HierarchyManipulations::computeLevels(points); updateSurpluses(points, top_level, level, dagUp); return; } bool is_complete = true; Data2D dagUp = HierarchyManipulations::computeDAGup(points, is_complete); if (not is_complete) { // incomplete hierarchy, must use the slow algorithm std::vector level = HierarchyManipulations::computeLevels(points); updateSurpluses(points, top_level, level, dagUp); return; } int num_nodes = 1 + *std::max_element(points.begin(), points.end()); std::vector vpntr, vindx; std::vector vvals; RuleLocal::van_matrix(order, num_nodes, vpntr, vindx, vvals); std::vector> map; std::vector> lines1d; MultiIndexManipulations::resortIndexes(points, map, lines1d); for(int d=num_dimensions-1; d>=0; d--) { #pragma omp parallel for schedule(dynamic) for(int job = 0; job < static_cast(lines1d[d].size() - 1); job++) { for(int i=lines1d[d][job]+1; i(); break; case RuleLocal::erule::localp: recomputeSurpluses(); break; case RuleLocal::erule::semilocalp: recomputeSurpluses(); break; case RuleLocal::erule::localp0: recomputeSurpluses(); break; default: // case RuleLocal::erule::localpb: recomputeSurpluses(); break; }; } template void GridLocalPolynomial::updateSurpluses(MultiIndexSet const &work, int max_level, std::vector const &level, Data2D const &dagUp){ int num_points = work.getNumIndexes(); int max_parents = num_dimensions * RuleLocal::getMaxNumParents(); std::vector> indexses_for_levels((size_t) max_level+1); for(int i=0; i 0) indexses_for_levels[level[i]].push_back(i); for(int l=1; l<=max_level; l++){ int level_size = (int) indexses_for_levels[l].size(); #pragma omp parallel { std::vector x(num_dimensions); std::vector monkey_count(max_level + 1); std::vector monkey_tail(max_level + 1); std::vector used(num_points, false); #pragma omp for schedule(dynamic) for(int s=0; s(pnt[j]); std::fill(used.begin(), used.end(), false); double *surpi = surpluses.getStrip(i); int current = 0; monkey_count[0] = 0; monkey_tail[0] = i; while(monkey_count[0] < max_parents){ if (monkey_count[current] < max_parents){ int branch = dagUp.getStrip(monkey_tail[current])[monkey_count[current]]; if ((branch == -1) || (used[branch])){ monkey_count[current]++; }else{ const double *branch_surp = surpluses.getStrip(branch); double basis_value = evalBasisRaw(work.getIndex(branch), x.data()); for(int k=0; k void GridLocalPolynomial::applyTransformationTransposed(double weights[], const MultiIndexSet &work, const std::vector &active_points) const { Data2D lparents = (parents.getNumStrips() != work.getNumIndexes()) ? // if the current dag loaded in parents does not reflect the indexes in work HierarchyManipulations::computeDAGup(work) : Data2D(); const Data2D &dagUp = (parents.getNumStrips() != work.getNumIndexes()) ? lparents : parents; std::vector level(active_points.size()); int active_top_level = 0; for(size_t i=0; i(p[0]); for(int j=1; j(p[j]); } if (active_top_level < current_level) active_top_level = current_level; level[i] = current_level; } std::vector monkey_count(top_level+1); std::vector monkey_tail(top_level+1); std::vector used(work.getNumIndexes()); int max_parents = RuleLocal::getMaxNumParents() * num_dimensions; std::vector node(num_dimensions); for(int l=active_top_level; l>0; l--){ for(size_t i=0; i(pnt[j]); std::fill(used.begin(), used.end(), false); monkey_count[0] = 0; monkey_tail[0] = active_points[i]; int current = 0; while(monkey_count[0] < max_parents){ if (monkey_count[current] < max_parents){ int branch = dagUp.getStrip(monkey_tail[current])[monkey_count[current]]; if ((branch == -1) || used[branch]){ monkey_count[current]++; }else{ const int *func = work.getIndex(branch); double basis_value = RuleLocal::evalRaw(order, func[0], node[0]); for(int j=1; j(order, func[j], node[j]); if (mode == 0) { weights[branch] -= weights[active_points[i]] * basis_value; } else { for (int d=0; d void GridLocalPolynomial::applyTransformationTransposed(double weights[], const MultiIndexSet &work, const std::vector &active_points) const { switch(effective_rule) { case RuleLocal::erule::pwc: applyTransformationTransposed(weights, work, active_points); break; case RuleLocal::erule::localp: applyTransformationTransposed(weights, work, active_points); break; case RuleLocal::erule::semilocalp: applyTransformationTransposed(weights, work, active_points); break; case RuleLocal::erule::localp0: applyTransformationTransposed(weights, work, active_points); break; default: // case RuleLocal::erule::localpb: applyTransformationTransposed(weights, work, active_points); break; }; } void GridLocalPolynomial::buildSpareBasisMatrix(const double x[], int num_x, int num_chunk, std::vector &spntr, std::vector &sindx, std::vector &svals) const{ std::vector> tindx; std::vector> tvals; std::vector numnz; buildSparseMatrixBlockForm(x, num_x, num_chunk, numnz, tindx, tvals); spntr = std::vector((size_t) num_x + 1); spntr[0] = 0; for(size_t i=1; i((size_t) spntr.back()); svals = std::vector((size_t) spntr.back()); auto ii = sindx.begin(); for(auto &idx : tindx) ii = std::copy(idx.begin(), idx.end(), ii); auto iv = svals.begin(); for(auto &vls : tvals) iv = std::copy(vls.begin(), vls.end(), iv); } void GridLocalPolynomial::buildSpareBasisMatrixStatic(const double x[], int num_x, int num_chunk, int *spntr, int *sindx, double *svals) const{ std::vector> tindx; std::vector> tvals; std::vector numnz; buildSparseMatrixBlockForm(x, num_x, num_chunk, numnz, tindx, tvals); int nz = 0; for(int i=0; i xwrap(num_dimensions, x); std::vector num_nz(num_x); #pragma omp parallel for for(int i=0; i sindx; std::vector svals; walkTree<1>(work, xwrap.getStrip(i), sindx, svals, nullptr); num_nz[i] = (int) sindx.size(); } return std::accumulate(num_nz.begin(), num_nz.end(), 0); } void GridLocalPolynomial::buildSparseMatrixBlockForm(const double x[], int num_x, int num_chunk, std::vector &numnz, std::vector> &tindx, std::vector> &tvals) const{ // numnz will be resized to (num_x + 1) with the last entry set to a dummy zero numnz.resize((size_t) num_x); int num_blocks = num_x / num_chunk + ((num_x % num_chunk != 0) ? 1 : 0); tindx.resize(num_blocks); tvals.resize(num_blocks); const MultiIndexSet &work = (points.empty()) ? needed : points; Utils::Wrapper2D xwrap(num_dimensions, x); #pragma omp parallel for for(int b=0; b(work, xwrap.getStrip(i), tindx[b], tvals[b], nullptr); numnz[i] = (int) tindx[b].size() - numnz[i]; } } } void GridLocalPolynomial::buildTree(){ const MultiIndexSet &work = (points.empty()) ? needed : points; int num_points = work.getNumIndexes(); Data2D kids; std::vector level; switch(effective_rule) { case RuleLocal::erule::pwc: kids = HierarchyManipulations::computeDAGDown(work); level = HierarchyManipulations::computeLevels(work); break; case RuleLocal::erule::localp: kids = HierarchyManipulations::computeDAGDown(work); level = HierarchyManipulations::computeLevels(work); break; case RuleLocal::erule::semilocalp: kids = HierarchyManipulations::computeDAGDown(work); level = HierarchyManipulations::computeLevels(work); break; case RuleLocal::erule::localp0: kids = HierarchyManipulations::computeDAGDown(work); level = HierarchyManipulations::computeLevels(work); break; default: // case RuleLocal::erule::localpb: kids = HierarchyManipulations::computeDAGDown(work); level = HierarchyManipulations::computeLevels(work); break; }; top_level = *std::max_element(level.begin(), level.end()); int max_kids = (int) kids.getStride(); Data2D tree(max_kids, num_points, -1); std::vector free(num_points, true); std::vector monkey_count((size_t) (top_level + 1)); std::vector monkey_tail(monkey_count.size()); roots = std::vector(); int next_root = 0; // zero is always a root and is included at index 0 while(next_root != -1){ roots.push_back(next_root); free[next_root] = false; monkey_tail[0] = next_root; monkey_count[0] = 0; size_t current = 0; while(monkey_count[0] < max_kids){ if (monkey_count[current] < max_kids){ int kid = kids.getStrip(monkey_tail[current])[monkey_count[current]]; if ((kid == -1) || (!free[kid])){ monkey_count[current]++; // no kid, keep counting }else{ tree.getStrip(monkey_tail[current])[monkey_count[current]] = kid; monkey_count[++current] = 0; monkey_tail[current] = kid; free[kid] = false; } }else{ monkey_count[--current]++; // done with all kids here } } next_root = -1; int next_level = top_level + 1; for(int i=0; i((size_t) (num_points + 1), 0); for(int i=0; ibool{ return (k > -1); }); indx = std::vector((size_t) ((pntr[num_points] > 0) ? pntr[num_points] : 1)); std::copy_if(tree.begin(), tree.end(), indx.begin(), [](int t)->bool{ return (t > -1); }); } void GridLocalPolynomial::integrateHierarchicalFunctions(double integrals[]) const{ const MultiIndexSet &work = (points.empty()) ? needed : points; std::vector w, x; if (order == -1 or order > 3) OneDimensionalNodes::getGaussLegendre(((order == -1) ? top_level : order) / 2 + 1, w, x); switch(effective_rule) { case RuleLocal::erule::pwc: #pragma omp parallel for for(int i=0; i(order, p[0], w, x); for(int j=1; j(order, p[j], w, x); } break; case RuleLocal::erule::localp: #pragma omp parallel for for(int i=0; i(order, p[0], w, x); for(int j=1; j(order, p[j], w, x); } break; case RuleLocal::erule::semilocalp: #pragma omp parallel for for(int i=0; i(order, p[0], w, x); for(int j=1; j(order, p[j], w, x); } break; case RuleLocal::erule::localp0: #pragma omp parallel for for(int i=0; i(order, p[0], w, x); for(int j=1; j(order, p[j], w, x); } break; default: // case RuleLocal::erule::localpb: #pragma omp parallel for for(int i=0; i(order, p[0], w, x); for(int j=1; j(order, p[j], w, x); } break; }; } template void GridLocalPolynomial::getQuadratureWeights(double *weights) const{ const MultiIndexSet &work = (points.empty()) ? needed : points; integrateHierarchicalFunctions(weights); std::vector monkey_count(top_level+1); std::vector monkey_tail(top_level+1); double basis_value; Data2D lparents; if (parents.getNumStrips() != work.getNumIndexes()) lparents = HierarchyManipulations::computeDAGup(work); const Data2D &dagUp = (parents.getNumStrips() != work.getNumIndexes()) ? lparents : parents; int num_points = work.getNumIndexes(); std::vector level = HierarchyManipulations::computeLevels(work); int max_parents = RuleLocal::getMaxNumParents() * num_dimensions; std::vector node(num_dimensions); std::vector used(work.getNumIndexes(), false); for(int l=top_level; l>0; l--){ for(int i=0; i(pnt[j]); std::fill(used.begin(), used.end(), false); monkey_count[0] = 0; monkey_tail[0] = i; int current = 0; while(monkey_count[0] < max_parents){ if (monkey_count[current] < max_parents){ int branch = dagUp.getStrip(monkey_tail[current])[monkey_count[current]]; if ((branch == -1) || used[branch]){ monkey_count[current]++; }else{ const int *func = work.getIndex(branch); basis_value = RuleLocal::evalRaw(order, func[0], node[0]); for(int j=1; j(order, func[j], node[j]); weights[branch] -= weights[i] * basis_value; used[branch] = true; monkey_count[++current] = 0; monkey_tail[current] = branch; } }else{ monkey_count[--current]++; } } } } } } void GridLocalPolynomial::getQuadratureWeights(double *weights) const{ switch(effective_rule) { case RuleLocal::erule::pwc: getQuadratureWeights(weights); break; case RuleLocal::erule::localp: getQuadratureWeights(weights); break; case RuleLocal::erule::semilocalp: getQuadratureWeights(weights); break; case RuleLocal::erule::localp0: getQuadratureWeights(weights); break; default: // case RuleLocal::erule::localpb: getQuadratureWeights(weights); break; }; } void GridLocalPolynomial::integrate(double q[], double *conformal_correction) const{ int num_points = points.getNumIndexes(); std::fill(q, q + num_outputs, 0.0); if (conformal_correction == 0){ std::vector integrals(num_points); integrateHierarchicalFunctions(integrals.data()); for(int i=0; i w(num_points); getQuadratureWeights(w.data()); for(int i=0; i sindx; std::vector svals; walkTree<3>(points, x, sindx, svals, jacobian); } std::vector GridLocalPolynomial::getNormalization() const{ std::vector norms(num_outputs); for(int i=0; i Data2D GridLocalPolynomial::buildUpdateMap(double tolerance, TypeRefinement criteria, int output, const double *scale_correction) const{ int num_points = points.getNumIndexes(); Data2D pmap(num_dimensions, num_points, std::vector(Utils::size_mult(num_dimensions, num_points), (tolerance == 0.0) ? 1 : 0) // tolerance 0 means "refine everything" ); if (tolerance == 0.0) return pmap; std::vector norm = getNormalization(); int active_outputs = (output == -1) ? num_outputs : 1; Utils::Wrapper2D scale(active_outputs, scale_correction); std::vector default_scale; if (scale_correction == nullptr){ default_scale = std::vector(Utils::size_mult(active_outputs, num_points), 1.0); scale = Utils::Wrapper2D(active_outputs, default_scale.data()); } if ((criteria == refine_classic) || (criteria == refine_parents_first)){ #pragma omp parallel for for(int i=0; i dagUp = HierarchyManipulations::computeDAGup(points); int max_1D_parents = RuleLocal::getMaxNumParents(); HierarchyManipulations::SplitDirections split(points); #pragma omp parallel { int max_nump = split.getMaxNumPoints(); std::vector global_to_pnts(num_points); std::vector levels(max_nump); std::vector monkey_count; std::vector monkey_tail; std::vector used; if (max_1D_parents > 1) { monkey_count.resize(top_level + 1); monkey_tail.resize(top_level + 1); used.resize(max_nump, false); } #pragma omp for for(int j=0; j vals(active_outputs, nump); if (output == -1) { for(int i=0; i(points.getIndex(pnts[i])[d]); if (max_level < levels[i]) max_level = levels[i]; } } else { for(int i=0; i(points.getIndex(pnts[i])[d]); if (max_level < levels[i]) max_level = levels[i]; } } if (max_1D_parents == 1) { for(int l=1; l<=max_level; l++){ for(int i=0; i(points.getIndex(pnts[i])[d]); double *valsi = vals.getStrip(i); int branch = dagUp.getStrip(pnts[i])[d]; while(branch != -1) { const int *branch_point = points.getIndex(branch); double basis_value = RuleLocal::evalRaw(order, branch_point[d], x); const double *branch_vals = vals.getStrip(global_to_pnts[branch]); for(int k=0; k(points.getIndex(pnts[i])[d]); double *valsi = vals.getStrip(i); int current = 0; monkey_count[0] = d * max_1D_parents; monkey_tail[0] = pnts[i]; // uses the global indexes std::fill_n(used.begin(), nump, false); while(monkey_count[0] < (d+1) * max_1D_parents){ if (monkey_count[current] < (d+1) * max_1D_parents){ int branch = dagUp.getStrip(monkey_tail[current])[monkey_count[current]]; if ((branch == -1) || (used[global_to_pnts[branch]])){ monkey_count[current]++; }else{ const int *branch_point = points.getIndex(branch); double basis_value = RuleLocal::evalRaw(order, branch_point[d], x); const double *branch_vals = vals.getStrip(global_to_pnts[branch]); for(int k=0; k MultiIndexSet GridLocalPolynomial::getRefinementCanidates(double tolerance, TypeRefinement criteria, int output, const std::vector &level_limits, const double *scale_correction) const{ Data2D pmap = buildUpdateMap(tolerance, criteria, output, scale_correction); bool useParents = (criteria == refine_fds) || (criteria == refine_parents_first); Data2D refined(num_dimensions, 0); int num_points = points.getNumIndexes(); #ifdef _OPENMP #pragma omp parallel { Data2D lrefined(num_dimensions, 0); if (level_limits.empty()){ #pragma omp for for(int i=0; i(points.getIndex(i), j, points, lrefined))){ addChild(points.getIndex(i), j, points, lrefined); } } } } }else{ #pragma omp for for(int i=0; i(points.getIndex(i), j, points, lrefined))){ addChildLimited(points.getIndex(i), j, points, level_limits, lrefined); } } } } } #pragma omp critical { refined.append(lrefined); } } #else if (level_limits.empty()){ for(int i=0; i(points.getIndex(i), j, points, refined))){ addChild(points.getIndex(i), j, points, refined); } } } } }else{ for(int i=0; i(points.getIndex(i), j, points, refined))){ addChildLimited(points.getIndex(i), j, points, level_limits, refined); } } } } } #endif MultiIndexSet result(refined); if (criteria == refine_stable) HierarchyManipulations::completeToLower(points, result); return result; } template bool GridLocalPolynomial::addParent(const int point[], int direction, const MultiIndexSet &exclude, Data2D &destination) const{ std::vector dad(point, point + num_dimensions); bool added = false; dad[direction] = RuleLocal::getParent(point[direction]); if ((dad[direction] != -1) && exclude.missing(dad)){ destination.appendStrip(dad); added = true; } dad[direction] = RuleLocal::getStepParent(point[direction]); if ((dad[direction] != -1) && exclude.missing(dad)){ destination.appendStrip(dad); added = true; } return added; } template void GridLocalPolynomial::addChild(const int point[], int direction, const MultiIndexSet &exclude, Data2D &destination) const{ std::vector kid(point, point + num_dimensions); int max_1d_kids = RuleLocal::getMaxNumKids(); for(int i=0; i(point[direction], i); if ((kid[direction] != -1) && exclude.missing(kid)){ destination.appendStrip(kid); } } } template void GridLocalPolynomial::addChildLimited(const int point[], int direction, const MultiIndexSet &exclude, const std::vector &level_limits, Data2D &destination) const{ std::vector kid(point, point + num_dimensions); int max_1d_kids = RuleLocal::getMaxNumKids(); for(int i=0; i(point[direction], i); if ((kid[direction] != -1) && ((level_limits[direction] == -1) || (RuleLocal::getLevel(kid[direction]) <= level_limits[direction])) && exclude.missing(kid)){ destination.appendStrip(kid); } } } void GridLocalPolynomial::clearRefinement(){ needed = MultiIndexSet(); } const double* GridLocalPolynomial::getSurpluses() const{ return surpluses.data(); } const int* GridLocalPolynomial::getNeededIndexes() const{ return (needed.empty()) ? 0 : needed.getIndex(0); } std::vector GridLocalPolynomial::getSupport() const{ MultiIndexSet const &work = (points.empty()) ? needed : points; std::vector support(Utils::size_mult(work.getNumIndexes(), work.getNumDimensions())); switch(effective_rule) { case RuleLocal::erule::pwc: std::transform(work.begin(), work.end(), support.begin(), [&](int p)->double{ return RuleLocal::getSupport(p); }); break; case RuleLocal::erule::localp: std::transform(work.begin(), work.end(), support.begin(), [&](int p)->double{ return RuleLocal::getSupport(p); }); break; case RuleLocal::erule::semilocalp: std::transform(work.begin(), work.end(), support.begin(), [&](int p)->double{ return RuleLocal::getSupport(p); }); break; case RuleLocal::erule::localp0: std::transform(work.begin(), work.end(), support.begin(), [&](int p)->double{ return RuleLocal::getSupport(p); }); break; default: // case RuleLocal::erule::localpb: std::transform(work.begin(), work.end(), support.begin(), [&](int p)->double{ return RuleLocal::getSupport(p); }); break; }; return support; } void GridLocalPolynomial::setSurplusRefinement(double tolerance, TypeRefinement criteria, int output, const std::vector &level_limits, const double *scale_correction){ clearRefinement(); switch(effective_rule) { case RuleLocal::erule::pwc: needed = getRefinementCanidates(tolerance, criteria, output, level_limits, scale_correction); break; case RuleLocal::erule::localp: needed = getRefinementCanidates(tolerance, criteria, output, level_limits, scale_correction); break; case RuleLocal::erule::semilocalp: needed = getRefinementCanidates(tolerance, criteria, output, level_limits, scale_correction); break; case RuleLocal::erule::localp0: needed = getRefinementCanidates(tolerance, criteria, output, level_limits, scale_correction); break; default: // case RuleLocal::erule::localpb: needed = getRefinementCanidates(tolerance, criteria, output, level_limits, scale_correction); break; }; } std::vector GridLocalPolynomial::getScaledCoefficients(int output, const double *scale_correction){ int num_points = points.getNumIndexes(); std::vector norm = getNormalization(); int active_outputs = (output == -1) ? num_outputs : 1; Utils::Wrapper2D scale(active_outputs, scale_correction); std::vector rescaled(num_points); for(int i=0; i rescaled = getScaledCoefficients(output, (scale_correction == nullptr) ? std::vector(num_points * active_outputs, 1.0).data() : scale_correction); std::vector pmap(num_points); // point map, set to true if the point is to be kept, false otherwise for(int i=0; i tolerance); return removeMappedPoints(pmap); } void GridLocalPolynomial::removePointsByHierarchicalCoefficient(int new_num_points, int output, const double *scale_correction){ clearRefinement(); int num_points = points.getNumIndexes(); int active_outputs = (output == -1) ? num_outputs : 1; std::vector rescaled = getScaledCoefficients(output, (scale_correction == nullptr) ? std::vector(num_points * active_outputs, 1.0).data() : scale_correction); std::vector> ordered(num_points); for(int i=0; i const& a, std::pair const& b) ->bool{ return (a.first > b.first); }); std::vector pmap(num_points, false); for(int i=0; i const &pmap){ int num_points = points.getNumIndexes(); int num_kept = 0; for(int i=0; i point_kept(num_dimensions, num_kept); StorageSet values_kept(num_outputs, num_kept, std::vector(Utils::size_mult(num_kept, num_outputs))); Data2D surpluses_kept(num_outputs, num_kept); for(int i=0, kept = 0; i(); surpluses.clear(); return 0; } points = MultiIndexSet(point_kept); values = std::move(values_kept); surpluses = std::move(surpluses_kept); buildTree(); return points.getNumIndexes(); } void GridLocalPolynomial::setHierarchicalCoefficients(const double c[]){ clearGpuSurpluses(); if (points.empty()){ points = std::move(needed); needed = MultiIndexSet(); }else{ clearRefinement(); } surpluses = Data2D(num_outputs, points.getNumIndexes(), std::vector(c, c + Utils::size_mult(num_outputs, points.getNumIndexes()))); std::vector x(Utils::size_mult(num_dimensions, points.getNumIndexes())); std::vector y(Utils::size_mult(num_outputs, points.getNumIndexes())); getPoints(x.data()); evaluateBatch(x.data(), points.getNumIndexes(), y.data()); values = StorageSet(num_outputs, points.getNumIndexes(), std::move(y)); } #ifdef Tasmanian_ENABLE_GPU void GridLocalPolynomial::updateAccelerationData(AccelerationContext::ChangeType change) const{ switch(change){ case AccelerationContext::change_gpu_device: gpu_cache.reset(); gpu_cachef.reset(); break; case AccelerationContext::change_sparse_dense: if (acceleration->algorithm_select == AccelerationContext::algorithm_dense){ // if forcing the dense algorithm then clear the hierarchy cache // note: the sparse algorithm uses both the hierarchy and the basis cache used in the dense mode if (gpu_cache) gpu_cache->clearHierarchy(); if (gpu_cachef) gpu_cachef->clearHierarchy(); } default: break; } } #else void GridLocalPolynomial::updateAccelerationData(AccelerationContext::ChangeType) const{} #endif } #endif TASMANIAN-8.1/SparseGrids/tsgGridLocalPolynomial.hpp000066400000000000000000000662401470551176200222760ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_LPOLY_HPP #define __TASMANIAN_SPARSE_GRID_LPOLY_HPP #include "tsgGridCore.hpp" namespace TasGrid{ #ifndef __TASMANIAN_DOXYGEN_SKIP class GridLocalPolynomial : public BaseCanonicalGrid{ public: GridLocalPolynomial(AccelerationContext const *acc) : BaseCanonicalGrid(acc), order(1), top_level(0){} friend struct GridReaderVersion5; GridLocalPolynomial(AccelerationContext const *acc, const GridLocalPolynomial *pwpoly, int ibegin, int iend); GridLocalPolynomial(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int depth, int corder, TypeOneDRule crule, const std::vector &level_limits); ~GridLocalPolynomial() = default; bool isLocalPolynomial() const override{ return true; } void write(std::ostream &os, bool iomode) const override{ if (iomode == mode_ascii) write(os); else write(os); } template void write(std::ostream &os) const; TypeOneDRule getRule() const override{ return RuleLocal::getRule(effective_rule); } int getOrder() const{ return order; } template void getPoints(double *x) const; void getLoadedPoints(double *x) const override; void getNeededPoints(double *x) const override; void getPoints(double *x) const override; // returns the loaded points unless no points are loaded, then returns the needed points template void getQuadratureWeights(double weights[]) const; void getQuadratureWeights(double weights[]) const override; void getInterpolationWeights(const double x[], double weights[]) const override; void getDifferentiationWeights(const double x[], double weights[]) const override; void loadNeededValues(const double *vals) override; void evaluate(const double x[], double y[]) const override; void integrate(double q[], double *conformal_correction) const override; void differentiate(const double x[], double jacobian[]) const override; void evaluateBatchOpenMP(const double x[], int num_x, double y[]) const; void evaluateBatch(const double x[], int num_x, double y[]) const override; void loadNeededValuesGPU(const double *vals); void evaluateGpuMixed(const double x[], int num_x, double y[]) const; void evaluateBatchGPU(const double gpu_x[], int cpu_num_x, double gpu_y[]) const override; void evaluateBatchGPU(const float gpu_x[], int cpu_num_x, float gpu_y[]) const override; template void evaluateBatchGPUtempl(const T gpu_x[], int cpu_num_x, T gpu_y[]) const; void evaluateHierarchicalFunctionsGPU(const double gpu_x[], int cpu_num_x, double *gpu_y) const override; void buildSparseBasisMatrixGPU(const double gpu_x[], int cpu_num_x, GpuVector &gpu_spntr, GpuVector &gpu_sindx, GpuVector &gpu_svals) const; void evaluateHierarchicalFunctionsGPU(const float gpu_x[], int cpu_num_x, float *gpu_y) const override; void buildSparseBasisMatrixGPU(const float gpu_x[], int cpu_num_x, GpuVector &gpu_spntr, GpuVector &gpu_sindx, GpuVector &gpu_svals) const; void setSurplusRefinement(double tolerance, TypeRefinement criteria, int output, const std::vector &level_limits, const double *scale_correction); void clearRefinement() override; void mergeRefinement() override; /*! * \brief Returns a vector with the normalized and rescaled coefficients. * * \param output indicates which output to use or can be -1 to indicate the use of all outputs (returns the max for each output) * \param scale_correction user provided corrections that rescale the coefficients by spacial or other importance */ std::vector getScaledCoefficients(int output, const double *scale_correction); int removePointsByHierarchicalCoefficient(double tolerance, int output, const double *scale_correction); // returns the number of points kept void removePointsByHierarchicalCoefficient(int new_num_points, int output, const double *scale_correction); /*! * \brief Remove all points marked as \b false in the \b pmap. * * \param pmap is a vector with size equal to the loaded points and flags as \b false each point that should be removed. */ int removeMappedPoints(std::vector const &pmap); void beginConstruction() override; void writeConstructionData(std::ostream &os, bool) const override; void readConstructionData(std::istream &is, bool) override; template std::vector getCandidateConstructionPoints(double tolerance, TypeRefinement criteria, int output, std::vector const &level_limits, double const *scale_correction); std::vector getCandidateConstructionPoints(double tolerance, TypeRefinement criteria, int output, std::vector const &level_limits, double const *scale_correction); template void loadConstructedPoint(const double x[], const std::vector &y); void loadConstructedPoint(const double x[], const std::vector &y) override; template void loadConstructedPoint(const double x[], int numx, const double y[]); void loadConstructedPoint(const double x[], int numx, const double y[]) override; void finishConstruction() override; void evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const override; std::vector getSupport() const override final; void setHierarchicalCoefficients(const double c[]) override; void integrateHierarchicalFunctions(double integrals[]) const override; void updateAccelerationData(AccelerationContext::ChangeType change) const override; const double* getSurpluses() const; const int* getNeededIndexes() const; void buildSpareBasisMatrix(const double x[], int num_x, int num_chunk, std::vector &spntr, std::vector &sindx, std::vector &svals) const; void buildSpareBasisMatrixStatic(const double x[], int num_x, int num_chunk, int *spntr, int *sindx, double *svals) const; int getSpareBasisMatrixNZ(const double x[], int num_x) const; protected: //! \brief Create a new grid with given parameters and moving the data out of the vectors and sets. GridLocalPolynomial(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int corder, TypeOneDRule crule, std::vector &&pnts, std::vector &&vals, std::vector &&surps); //! \brief Used as part of the loadNeededPoints() algorithm, updates the values and cuda cache, but does not touch the surpluses. void updateValues(double const *vals); void buildTree(); //! \brief Returns a list of indexes of the nodes in \b points that are descendants of the \b point. template std::vector getSubGraph(std::vector const &point) const; //! \brief Add the \b point to the grid using the \b values. template void expandGrid(std::vector const &point, std::vector const &value); //! \brief Return the multi-index of canonical point \b x. template std::vector getMultiIndex(const double x[]); //! \brief Looks for a batch of constructed points and processes all that will result in a connected graph. template void loadConstructedPoints(); //! \brief Fast algorithm, uses global Kronecker algorithm to recompute all surpluses template void recomputeSurpluses(); void recomputeSurpluses(); /*! * \brief Update the surpluses for a portion of the graph. * * Updates the surpluses (i.e., hierarchical coefficients) for a portion of the DAG graph. * - \b work is the point set to consider * - \b max_level is the largest element in \b level * - \b level is the hierarchical level of the points in \b work (i.e., not the sum of multi-index entries); * points where \b level is zero will not be computed * - \b dagUp must have been computed using \b MultiIndexManipulations::computeDAGup(\b work, \b rule, \b dagUp) * * Note: adjusting the \b level vector allows to update the surpluses for only a portion of the graph. * * Note: see the comments inside recomputeSurpluses() for the performance comparison between different algorithms * also note that this method can be used to partially update, i.e., update the surpluses for some of the indexes */ template void updateSurpluses(MultiIndexSet const &work, int max_level, std::vector const &level, Data2D const &dagUp); // Same idea as in GridSequence::applyTransformationTransposed(). template void applyTransformationTransposed(double weights[], const MultiIndexSet &work, const std::vector &active_points) const; template void applyTransformationTransposed(double weights[], const MultiIndexSet &work, const std::vector &active_points) const; void buildSparseMatrixBlockForm(const double x[], int num_x, int num_chunk, std::vector &numnz, std::vector> &tindx, std::vector> &tvals) const; template double evalBasisSupported(const int point[], const double x[], bool &isSupported) const{ double f = RuleLocal::evalSupport(order, point[0], x[0], isSupported); if (!isSupported) return 0.0; for(int j=1; j(order, point[j], x[j], isSupported); if (!isSupported) return 0.0; } return f; } template void diffBasisSupported(const int point[], const double x[], double diff_values[], bool &isSupported) const{ isSupported = false; for(int i=0; i(order, point[k], x[k], isDimSupported); isSupported = isDimSupported or isSupported; for(int j=0; j(order, point[k], x[k], isDimSupported); isSupported = isDimSupported or isSupported; } } /*! * \brief Walk through all the nodes of the tree and touches only the nodes supported at \b x. * * The template is instantiated in different modes: * - \b mode \b 0, ignore \b sindx and \b svals, find the non-zero basis functions multiply them by the surpluses and add to \b y * - \b mode \b 1, ignore \b y, form a sparse vector by std::vector::push_back() to the \b sindx and \b svals * - \b mode \b 2, same as \b mode \b 1 but it also sorts the entries within the vector (requirement of Nvidia cusparseDgemvi) * - \b mode \b 3, same as \b mode \b 0, but replaces the non-zero basis function values with their gradient vectors * - \b mode \b 4, same as \b mode \b 1, but replaces the non-zero basis function values with their gradient vectors * * For mode 4, the i-th entry of sindx maps to the set of num_dimension values in svals at index (i * num_dimension). Hence, * we have (sindx.size() * num_dimensions == svals.size()). * * In all cases, \b work is the \b points or \b needed set that has been used to construct the tree. */ template void walkTree(const MultiIndexSet &work, const double x[], std::vector &sindx, std::vector &svals, double *y) const{ std::vector monkey_count(top_level+1); // traverse the tree, counts the branches of the current node std::vector monkey_tail(top_level+1); // traverse the tree, keeps track of the previous node (history) bool isSupported; double basis_value; std::vector basis_derivative(num_dimensions); for(const auto &r : roots){ if (mode == 3 or mode == 4) { diffBasisSupported(work.getIndex(r), x, basis_derivative.data(), isSupported); } else { basis_value = evalBasisSupported(work.getIndex(r), x, isSupported); } if (isSupported){ if (mode == 0){ double const *s = surpluses.getStrip(r); for(int k=0; k(work.getIndex(p), x, basis_derivative.data(), isSupported); }else{ basis_value = evalBasisSupported(work.getIndex(p), x, isSupported); } if (isSupported){ if (mode == 0){ double const *s = surpluses.getStrip(p); for(int k=0; k map(sindx); std::iota(map.begin(), map.end(), 0); std::sort(map.begin(), map.end(), [&](int a, int b)->bool{ return (sindx[a] < sindx[b]); }); std::vector idx = sindx; std::vector vls = svals; std::transform(map.begin(), map.end(), sindx.begin(), [&](int i)->int{ return idx[i]; }); std::transform(map.begin(), map.end(), svals.begin(), [&](int i)->double{ return vls[i]; }); } } // Explicitly instantiates based on the effective_rule template void walkTree(const MultiIndexSet &work, const double x[], std::vector &sindx, std::vector &svals, double *y) const{ switch(effective_rule) { case RuleLocal::erule::pwc: walkTree(work,x, sindx, svals, y); break; case RuleLocal::erule::localp: walkTree(work,x, sindx, svals, y); break; case RuleLocal::erule::semilocalp: walkTree(work,x, sindx, svals, y); break; case RuleLocal::erule::localp0: walkTree(work,x, sindx, svals, y); break; default: // case RuleLocal::erule::localpb: walkTree(work,x, sindx, svals, y); break; }; } template double evalBasisRaw(const int point[], const double x[]) const { double f = RuleLocal::evalRaw(order, point[0], x[0]); for(int j=1; j(order, point[j], x[j]); return f; } std::vector getNormalization() const; template Data2D buildUpdateMap(double tolerance, TypeRefinement criteria, int output, const double *scale_correction) const; template MultiIndexSet getRefinementCanidates(double tolerance, TypeRefinement criteria, int output, const std::vector &level_limits, const double *scale_correction) const; template bool addParent(const int point[], int direction, const MultiIndexSet &exclude, Data2D &destination) const; template void addChild(const int point[], int direction, const MultiIndexSet &exclude, Data2D &destination) const; template void addChildLimited(const int point[], int direction, const MultiIndexSet &exclude, const std::vector &level_limits, Data2D &destination) const; void clearGpuSurpluses(); void clearGpuBasisHierarchy(); private: int order, top_level; Data2D surpluses; Data2D parents; // tree for evaluation std::vector roots; std::vector pntr; std::vector indx; RuleLocal::erule effective_rule; std::unique_ptr dynamic_values; // synchronize with tasgpu_devalpwpoly_feval template Data2D encodeSupportForGPU(const MultiIndexSet &work) const{ Data2D cpu_support(num_dimensions, work.getNumIndexes()); for(int i=0; i(RuleLocal::getSupport(p[j])); } else { switch(crule) { case rule_localp: s[j] = static_cast(RuleLocal::getSupport(p[j])); break; case rule_semilocalp: s[j] = static_cast(RuleLocal::getSupport(p[j])); break; case rule_localp0: s[j] = static_cast(RuleLocal::getSupport(p[j])); break; case rule_localpb: s[j] = static_cast(RuleLocal::getSupport(p[j])); break; }; if (ord == 2) s[j] *= s[j]; if ((crule == rule_localp) || (crule == rule_semilocalp)) if (p[j] == 0) s[j] = static_cast(-1.0); // constant function if ((crule == rule_localp) && (ord == 2)){ if (p[j] == 1) s[j] = static_cast(-2.0); else if (p[j] == 2) s[j] = static_cast(-3.0); } if ((crule == rule_semilocalp) && (ord == 2)){ if (p[j] == 1) s[j] = static_cast(-4.0); else if (p[j] == 2) s[j] = static_cast(-5.0); } if ((crule == rule_localpb) && (ord == 2)){ if (p[j] < 2) s[j] = static_cast(-2.0); // linear functions on level 0 } } } } return cpu_support; } std::unique_ptr>& getGpuCacheOverload(double) const{ return gpu_cache; } std::unique_ptr>& getGpuCacheOverload(float) const{ return gpu_cachef; } template std::unique_ptr>& getGpuCache() const{ return getGpuCacheOverload(static_cast(0.0)); } template void loadGpuBasis() const; template void loadGpuHierarchy() const; template void loadGpuSurpluses() const; mutable std::unique_ptr> gpu_cache; mutable std::unique_ptr> gpu_cachef; }; // Old version reader template<> struct GridReaderVersion5{ template static std::unique_ptr read(AccelerationContext const *acc, std::istream &is){ std::unique_ptr grid = Utils::make_unique(acc); grid->num_dimensions = IO::readNumber(is); grid->num_outputs = IO::readNumber(is); grid->order = IO::readNumber(is); grid->top_level = IO::readNumber(is); TypeOneDRule rule = IO::readRule(is); grid->effective_rule = RuleLocal::getEffectiveRule(grid->order, rule); if (IO::readFlag(is)) grid->points = MultiIndexSet(is, iomode()); if (std::is_same::value){ // backwards compatible: surpluses and needed, or needed and surpluses if (IO::readFlag(is)) grid->surpluses = IO::readData2D(is, grid->num_outputs, grid->points.getNumIndexes()); if (IO::readFlag(is)) grid->needed = MultiIndexSet(is, iomode()); }else{ if (IO::readFlag(is)) grid->needed = MultiIndexSet(is, iomode()); if (IO::readFlag(is)) grid->surpluses = IO::readData2D(is, grid->num_outputs, grid->points.getNumIndexes()); } int max_parents = [&]()->int { switch(grid->effective_rule) { case RuleLocal::erule::pwc: return RuleLocal::getMaxNumParents(); case RuleLocal::erule::localp: return RuleLocal::getMaxNumParents(); case RuleLocal::erule::semilocalp: return RuleLocal::getMaxNumParents(); case RuleLocal::erule::localp0: return RuleLocal::getMaxNumParents(); default: // case RuleLocal::erule::localpb: return RuleLocal::getMaxNumParents(); }; }(); if (IO::readFlag(is)) grid->parents = IO::readData2D(is, max_parents * grid->num_dimensions, grid->points.getNumIndexes()); size_t num_points = (size_t) ((grid->points.empty()) ? grid->needed.getNumIndexes() : grid->points.getNumIndexes()); grid->roots = std::vector((size_t) IO::readNumber(is)); if (grid->roots.size() > 0){ IO::readVector(is, grid->roots); grid->pntr = IO::readVector(is, num_points + 1); if (grid->pntr[num_points] > 0){ grid->indx = IO::readVector(is, grid->pntr[num_points]); }else{ grid->indx = IO::readVector(is, 1); } } if (grid->num_outputs > 0) grid->values = StorageSet(is, iomode()); return grid; } }; #endif // __TASMANIAN_DOXYGEN_SKIP } #endif TASMANIAN-8.1/SparseGrids/tsgGridSequence.cpp000066400000000000000000001162321470551176200207400ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_GLOBAL_NESTED_CPP #define __TASMANIAN_SPARSE_GRID_GLOBAL_NESTED_CPP #include "tsgGridSequence.hpp" #include "tsgTPLWrappers.hpp" namespace TasGrid{ template void GridSequence::write(std::ostream &os) const{ if (iomode == mode_ascii){ os << std::scientific; os.precision(17); } IO::writeNumbers(os, num_dimensions, num_outputs); IO::writeRule(rule, os); IO::writeFlag(!points.empty(), os); if (!points.empty()) points.write(os); IO::writeFlag(!needed.empty(), os); if (!needed.empty()) needed.write(os); IO::writeFlag(!surpluses.empty(), os); if (!surpluses.empty()) surpluses.writeVector(os); if (num_outputs > 0) values.write(os); } template void GridSequence::write(std::ostream &) const; template void GridSequence::write(std::ostream &) const; void GridSequence::clearRefinement(){ needed = MultiIndexSet(); } inline MultiIndexSet makeSequenceSet(int cnum_dimensions, int depth, TypeDepth type, TypeOneDRule crule, const std::vector &anisotropic_weights, const std::vector &level_limits){ return (OneDimensionalMeta::isExactQuadrature(type)) ? MultiIndexManipulations::selectTensors((size_t) cnum_dimensions, depth, type, [&](int i) -> int{ return OneDimensionalMeta::getQExact(i, crule); }, anisotropic_weights, level_limits) : MultiIndexManipulations::selectTensors((size_t) cnum_dimensions, depth, type, [&](int i) -> int{ return i; }, anisotropic_weights, level_limits); } GridSequence::GridSequence(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int depth, TypeDepth type, TypeOneDRule crule, const std::vector &anisotropic_weights, const std::vector &level_limits) : BaseCanonicalGrid(acc, cnum_dimensions, cnum_outputs, MultiIndexSet(), makeSequenceSet(cnum_dimensions, depth, type, crule, anisotropic_weights, level_limits), StorageSet()), rule(crule){ values.resize(num_outputs, needed.getNumIndexes()); prepareSequence(0); } GridSequence::GridSequence(AccelerationContext const *acc, int cnum_dimensions, int depth, TypeDepth type, TypeOneDRule crule, const std::vector &anisotropic_weights, const std::vector &level_limits) : BaseCanonicalGrid(acc, cnum_dimensions, 0, makeSequenceSet(cnum_dimensions, depth, type, crule, anisotropic_weights, level_limits), MultiIndexSet(), StorageSet()), rule(crule){ prepareSequence(0); } GridSequence::GridSequence(AccelerationContext const *acc, MultiIndexSet &&pset, int cnum_outputs, TypeOneDRule crule) : BaseCanonicalGrid(acc, static_cast(pset.getNumDimensions()), cnum_outputs, (cnum_outputs == 0) ? std::move(pset) : MultiIndexSet(), (cnum_outputs == 0) ? MultiIndexSet() : std::move(pset), StorageSet()), rule(crule) { if (num_outputs > 0) values.resize(num_outputs, needed.getNumIndexes()); prepareSequence(0); } GridSequence::GridSequence(AccelerationContext const *acc, GridSequence const *seq, int ibegin, int iend) : BaseCanonicalGrid(acc, *seq, ibegin, iend), rule(seq->rule), surpluses((num_outputs == seq->num_outputs) ? seq->surpluses : seq->surpluses.splitData(ibegin, iend)), nodes(seq->nodes), coeff(seq->coeff), max_levels(seq->max_levels){ if (seq->dynamic_values){ dynamic_values = Utils::make_unique(*seq->dynamic_values); if (num_outputs != seq->num_outputs) dynamic_values->restrictData(ibegin, iend); } } void GridSequence::updateGrid(int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ clearRefinement(); MultiIndexSet pset = makeSequenceSet(num_dimensions, depth, type, rule, anisotropic_weights, level_limits); if ((num_outputs == 0) || (points.empty())){ if (num_outputs == 0){ points = std::move(pset); needed = MultiIndexSet(); }else{ points = MultiIndexSet(); needed = std::move(pset); values.resize(num_outputs, needed.getNumIndexes()); } nodes = std::vector(); coeff = std::vector(); surpluses = Data2D(); prepareSequence(0); }else{ pset += points; needed = pset - points; if (!needed.empty()) prepareSequence(0); } } void GridSequence::getLoadedPoints(double *x) const{ MultiIndexManipulations::indexesToNodes(points, *this, x); } void GridSequence::getNeededPoints(double *x) const{ MultiIndexManipulations::indexesToNodes(needed, *this, x); } void GridSequence::getPoints(double *x) const{ if (points.empty()){ getNeededPoints(x); }else{ getLoadedPoints(x); } } void GridSequence::getQuadratureWeights(double *weights) const{ const MultiIndexSet& work = (points.empty()) ? needed : points; std::vector integ = cacheBasisIntegrals(); int n = work.getNumIndexes(); for(int i=0; i(weights); } void GridSequence::getInterpolationWeights(const double x[], double *weights) const{ std::vector> cache = cacheBasisValues(x); const MultiIndexSet& work = (points.empty()) ? needed : points; int n = work.getNumIndexes(); weights[0] = 1.0; for(int i=1; i(weights); } void GridSequence::getDifferentiationWeights(const double x[], double weights[]) const { std::vector> value_cache = cacheBasisValues(x); std::vector> derivative_cache = cacheBasisDerivatives(x); std::vector diff_values(num_dimensions); const MultiIndexSet& work = (points.empty()) ? needed : points; int n = work.getNumIndexes(); std::fill_n(weights, n * num_dimensions, 0.0); for(int i=0; i(weights); } void GridSequence::loadNeededValues(const double *vals){ clearGpuSurpluses(); // changing values and surpluses, clear the cache if (needed.empty()){ // overwrite the existing values values.setValues(vals); }else{ clearGpuNodes(); // the points and needed will change, clear the cache if (points.empty()){ // initial grid, just relabel needed as points (loaded) values.setValues(vals); points = std::move(needed); needed = MultiIndexSet(); }else{ // merge needed and points values.addValues(points, needed, vals); points += needed; needed = MultiIndexSet(); prepareSequence(0); } } recomputeSurpluses(); } void GridSequence::mergeRefinement(){ if (needed.empty()) return; // nothing to do clearGpuSurpluses(); // clear the surpluses (all values have cleared) int num_all_points = getNumLoaded() + getNumNeeded(); size_t num_vals = ((size_t) num_all_points) * ((size_t) num_outputs); values.setValues(std::vector(num_vals, 0.0)); if (points.empty()){ // relabel needed as points (loaded) points = std::move(needed); needed = MultiIndexSet(); }else{ clearGpuNodes(); // the points will change, clear cache points += needed; needed = MultiIndexSet(); prepareSequence(0); } surpluses = Data2D(num_outputs, num_all_points); } void GridSequence::beginConstruction(){ dynamic_values = Utils::make_unique(); if (points.empty()){ dynamic_values->initial_points = std::move(needed); needed = MultiIndexSet(); } } void GridSequence::writeConstructionData(std::ostream &os, bool iomode) const{ if (iomode == mode_ascii) dynamic_values->write(os); else dynamic_values->write(os); } void GridSequence::readConstructionData(std::istream &is, bool iomode){ if (iomode == mode_ascii) dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_ascii_type()); else dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_binary_type()); } std::vector GridSequence::getCandidateConstructionPoints(TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits){ MultiIndexManipulations::ProperWeights weights((size_t) num_dimensions, type, anisotropic_weights); auto level_exact = [&](int l) -> int{ return l; }; auto quad_exact = [&](int l) -> int{ return OneDimensionalMeta::getQExact(l, rule); }; if (weights.contour == type_level){ std::vector> cache; return getCandidateConstructionPoints([&](int const *t) -> double{ // see the same named function in GridGlobal if (cache.empty()){ if (OneDimensionalMeta::isExactQuadrature(type)){ cache = MultiIndexManipulations::generateLevelWeightsCache(weights, quad_exact, (int) nodes.size()); }else{ cache = MultiIndexManipulations::generateLevelWeightsCache(weights, level_exact, (int) nodes.size()); } } int w = 0; for(int j=0; j> cache; return getCandidateConstructionPoints([&](int const *t) -> double{ // see the same named function in GridGlobal if (cache.empty()){ if (OneDimensionalMeta::isExactQuadrature(type)){ cache = MultiIndexManipulations::generateLevelWeightsCache(weights, quad_exact, (int) nodes.size()); }else{ cache = MultiIndexManipulations::generateLevelWeightsCache(weights, level_exact, (int) nodes.size()); } } double w = 0.0; for(int j=0; j> cache; return getCandidateConstructionPoints([&](int const *t) -> double{ // see the same named function in GridGlobal if (cache.empty()){ if (OneDimensionalMeta::isExactQuadrature(type)){ cache = MultiIndexManipulations::generateLevelWeightsCache(weights, quad_exact, (int) nodes.size()); }else{ cache = MultiIndexManipulations::generateLevelWeightsCache(weights, level_exact, (int) nodes.size()); } } double w = 1.0; for(int j=0; j GridSequence::getCandidateConstructionPoints(TypeDepth type, int output, const std::vector &level_limits){ std::vector weights; if ((type == type_iptotal) || (type == type_ipcurved) || (type == type_qptotal) || (type == type_qpcurved)){ int min_needed_points = ((type == type_ipcurved) || (type == type_qpcurved)) ? 4 * num_dimensions : 2 * num_dimensions; if (points.getNumIndexes() > min_needed_points) // if there are enough points to estimate coefficients estimateAnisotropicCoefficients(type, output, weights); } return getCandidateConstructionPoints(type, weights, level_limits); } std::vector GridSequence::getCandidateConstructionPoints(std::function getTensorWeight, const std::vector &level_limits){ // get the new candidate points that will ensure lower completeness and are not included in the initial set MultiIndexSet new_points = (level_limits.empty()) ? MultiIndexManipulations::addExclusiveChildren(points, dynamic_values->initial_points, level_limits) : MultiIndexManipulations::addExclusiveChildren(points, dynamic_values->initial_points, level_limits); prepareSequence(std::max(new_points.getMaxIndex(), dynamic_values->initial_points.getMaxIndex())); std::forward_list weighted_points; // use the values as the weight for(int i=0; iinitial_points.getNumIndexes(); i++){ std::vector p = dynamic_values->initial_points.copyIndex(i); weighted_points.push_front({p, {-1.0 / ((double) std::accumulate(p.begin(), p.end(), 0))}}); } for(int i=0; i p = new_points.copyIndex(i); weighted_points.push_front({p, {getTensorWeight(p.data())}}); } weighted_points.sort([&](const NodeData &a, const NodeData &b)->bool{ return (a.value[0] < b.value[0]); }); return listToNodes(weighted_points, num_dimensions, *this); } std::vector GridSequence::getMultiIndex(const double x[]){ std::vector p(num_dimensions); for(int j=0; j Maths::num_tol){ i++; // convert canonical node to index if (i == (int) nodes.size()) prepareSequence(i); } p[j] = i; } return p; } void GridSequence::loadConstructedPoint(const double x[], const std::vector &y){ std::vector p = getMultiIndex(x); std::vector scratch(num_dimensions); if (MultiIndexManipulations::isLowerComplete(p, points, scratch)){ std::vector approx_value(num_outputs), surplus(num_outputs);; if (!points.empty()){ evaluate(x, approx_value.data()); std::transform(approx_value.begin(), approx_value.end(), y.begin(), surplus.begin(), [&](double e, double v)->double{ return v - e; }); } expandGrid(p, y, surplus); dynamic_values->initial_points.removeIndex(p); loadConstructedPoints(); // batch operation, if the new point has unleashed a bunch of previously available ones }else{ dynamic_values->data.push_front({p, y}); dynamic_values->initial_points.removeIndex(p); } } void GridSequence::loadConstructedPoint(const double x[], int numx, const double y[]){ Utils::Wrapper2D wrapx(num_dimensions, x); std::vector> pnts(numx); for(int i=0; iinitial_points.empty()){ Data2D combined_pnts(num_dimensions, numx); for(int i=0; iinitial_points = dynamic_values->initial_points - combined_pnts; } Utils::Wrapper2D wrapy(num_outputs, y); for(int i=0; idata.push_front({std::move(pnts[i]), std::vector(wrapy.getStrip(i), wrapy.getStrip(i) + num_outputs)}); loadConstructedPoints(); } void GridSequence::expandGrid(const std::vector &point, const std::vector &value, const std::vector &surplus){ if (points.empty()){ // only one point points = MultiIndexSet((size_t) num_dimensions, std::vector(point)); values = StorageSet(num_outputs, 1, std::vector(value)); surpluses = Data2D(num_outputs, 1, std::vector(value.begin(), value.end())); // the surplus of one point is the value itself }else{ // merge with existing points MultiIndexSet temp(num_dimensions, std::vector(point)); values.addValues(points, temp, value.data()); points.addSortedIndexes(point); surpluses.appendStrip(points.getSlot(point), surplus); } prepareSequence(0); // update the directional max_levels, will not shrink the number of nodes } void GridSequence::loadConstructedPoints(){ Data2D candidates(num_dimensions, 0); for(auto &d : dynamic_values->data) candidates.appendStrip(d.point); auto new_points = MultiIndexManipulations::getLargestCompletion(points, MultiIndexSet(candidates)); if (new_points.empty()) return; clearGpuNodes(); // the points will change, clear the cache clearGpuSurpluses(); auto vals = dynamic_values->extractValues(new_points); if (points.empty()){ points = std::move(new_points); values.setValues(std::move(vals)); }else{ values.addValues(points, new_points, vals.data()); points += new_points; } prepareSequence(0); // update the directional max_levels, will not shrink the number of nodes recomputeSurpluses(); // costly, but the only option under the circumstances } void GridSequence::finishConstruction(){ dynamic_values.reset(); } void GridSequence::evaluate(const double x[], double y[]) const{ std::vector> cache = cacheBasisValues(x); std::fill(y, y + num_outputs, 0.0); int num_points = points.getNumIndexes(); for(int i=0; imode){ case accel_gpu_magma: case accel_gpu_cuda: { acceleration->setDevice(); GpuVector gpu_x(acceleration, num_dimensions, num_x, x), gpu_result(acceleration, num_outputs, num_x); evaluateBatchGPU(gpu_x.data(), num_x, gpu_result.data()); gpu_result.unload(acceleration, y); break; } case accel_gpu_cublas: { acceleration->setDevice(); loadGpuSurpluses(); Data2D hweights(points.getNumIndexes(), num_x); evaluateHierarchicalFunctions(x, num_x, hweights.data()); TasGpu::denseMultiplyMixed(acceleration, num_outputs, num_x, points.getNumIndexes(), 1.0, gpu_cache->surpluses, hweights.data(), 0.0, y); break; } case accel_cpu_blas: { int num_points = points.getNumIndexes(); Data2D weights(num_points, num_x); if (num_x > 1) evaluateHierarchicalFunctions(x, num_x, weights.data()); else // workaround small OpenMP penalty evalHierarchicalFunctions(x, weights.data()); TasBLAS::denseMultiply(num_outputs, num_x, num_points, 1.0, surpluses.data(), weights.data(), 0.0, y); break; } default: { Utils::Wrapper2D xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(num_outputs, y); #pragma omp parallel for for(int i=0; i void GridSequence::evaluateBatchGPUtempl(const T gpu_x[], int cpu_num_x, T gpu_y[]) const{ loadGpuSurpluses(); GpuVector gpu_basis(acceleration, points.getNumIndexes(), cpu_num_x); evaluateHierarchicalFunctionsGPU(gpu_x, cpu_num_x, gpu_basis.data()); TasGpu::denseMultiply(acceleration, num_outputs, cpu_num_x, points.getNumIndexes(), 1.0, getGpuCache()->surpluses, gpu_basis, 0.0, gpu_y); } void GridSequence::evaluateBatchGPU(const double gpu_x[], int cpu_num_x, double gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridSequence::evaluateHierarchicalFunctionsGPU(const double gpu_x[], int num_x, double gpu_y[]) const{ loadGpuNodes(); TasGpu::devalseq(acceleration, num_dimensions, num_x, max_levels, gpu_x, gpu_cache->num_nodes, gpu_cache->points, gpu_cache->nodes, gpu_cache->coeff, gpu_y); } void GridSequence::evaluateBatchGPU(const float gpu_x[], int cpu_num_x, float gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridSequence::evaluateHierarchicalFunctionsGPU(const float gpu_x[], int num_x, float gpu_y[]) const{ loadGpuNodes(); TasGpu::devalseq(acceleration, num_dimensions, num_x, max_levels, gpu_x, gpu_cachef->num_nodes, gpu_cachef->points, gpu_cachef->nodes, gpu_cachef->coeff, gpu_y); } void GridSequence::clearGpuNodes() const{ if (gpu_cache) gpu_cache->clearNodes(); if (gpu_cachef) gpu_cachef->clearNodes(); } void GridSequence::clearGpuSurpluses() const{ if (gpu_cache) gpu_cache->surpluses.clear(); if (gpu_cachef) gpu_cachef->surpluses.clear(); } void GridSequence::integrate(double q[], double *conformal_correction) const{ int num_points = points.getNumIndexes(); std::fill(q, q + num_outputs, 0.0); // for sequence grids, quadrature weights are expensive, // if using simple integration use the basis integral + surpluses, which is fast // if using conformal map, then we have to compute the expensive weights if (conformal_correction == 0){ std::vector integ = cacheBasisIntegrals(); for(int i=0; i w(num_points); getQuadratureWeights(w.data()); for(int i=0; i> value_cache = cacheBasisValues(x); std::vector> derivative_cache = cacheBasisDerivatives(x); std::vector diff_values(num_dimensions); std::fill_n(jacobian, num_outputs * num_dimensions, 0.0); int n = points.getNumIndexes(); for(int i=0; i xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(num_points, y); #pragma omp parallel for for(int i=0; i> cache = cacheBasisValues(x); for(int i=0; i(num_outputs, num_points, std::vector(c, c + Utils::size_mult(num_outputs, num_points))); std::vector x(Utils::size_mult(num_dimensions, num_points)); std::vector y(Utils::size_mult(num_outputs, num_points)); getPoints(x.data()); evaluateBatch(x.data(), points.getNumIndexes(), y.data()); // speed this up later values = StorageSet(num_outputs, num_points, std::move(y)); } void GridSequence::integrateHierarchicalFunctions(double integrals[]) const{ const MultiIndexSet& work = (points.empty()) ? needed : points; int const num_points = work.getNumIndexes(); std::vector integ = cacheBasisIntegrals(); for(int i=0; i &weights) const{ double tol = 1000 * Maths::num_tol; int num_points = points.getNumIndexes(); std::vector max_surp(num_points); if (output == -1){ std::vector nrm(num_outputs, 0.0); for(int i=0; i &level_limits){ clearRefinement(); std::vector weights; estimateAnisotropicCoefficients(type, output, weights); int level = 0; do{ updateGrid(++level, type, weights, level_limits); }while(getNumNeeded() < min_growth); } void GridSequence::setSurplusRefinement(double tolerance, int output, const std::vector &level_limits){ clearRefinement(); int num_points = points.getNumIndexes(); std::vector flagged(num_points); std::vector norm(num_outputs, 0.0); for(int i=0; i tolerance); } }else{ for(int i=0; i tolerance); } } MultiIndexSet kids = MultiIndexManipulations::selectFlaggedChildren(points, flagged, level_limits); if (kids.getNumIndexes() > 0){ kids += points; MultiIndexManipulations::completeSetToLower(kids); needed = kids - points; if (!needed.empty()) prepareSequence(0); } } std::vector GridSequence::getPolynomialSpace(bool interpolation) const{ if (interpolation){ return (points.empty()) ? std::vector(needed.begin(), needed.end()) : std::vector(points.begin(), points.end()); // copy }else{ MultiIndexSet polynomial_set = MultiIndexManipulations::createPolynomialSpace( (points.empty()) ? needed : points, [&](int l) -> int{ return OneDimensionalMeta::getQExact(l, rule); }); return polynomial_set.release(); } } const double* GridSequence::getSurpluses() const{ return surpluses.data(); } void GridSequence::prepareSequence(int num_external){ int mp = 0, mn = 0, max_level; if (needed.empty()){ // points must be non-empty if (points.empty()){ max_levels.resize(num_dimensions, 0); }else{ max_levels = MultiIndexManipulations::getMaxIndexes(points); mp = *std::max_element(max_levels.begin(), max_levels.end()); } }else if (points.empty()){ // only needed, no points (right after creation) max_levels = MultiIndexManipulations::getMaxIndexes(needed); mn = *std::max_element(max_levels.begin(), max_levels.end()); }else{ // both points and needed are set max_levels = MultiIndexManipulations::getMaxIndexes(points); mp = *std::max_element(max_levels.begin(), max_levels.end()); mn = needed.getMaxIndex(); } max_level = (mp > mn) ? mp : mn; if (max_level < num_external) max_level = num_external; max_level++; if ((size_t) max_level > nodes.size()){ if (rule == rule_leja){ nodes = Optimizer::getGreedyNodes(max_level); }else if (rule == rule_maxlebesgue){ nodes = Optimizer::getGreedyNodes(max_level); }else if (rule == rule_minlebesgue){ nodes = Optimizer::getGreedyNodes(max_level); }else if (rule == rule_mindelta){ nodes = Optimizer::getGreedyNodes(max_level); }else if (rule == rule_rleja){ nodes = OneDimensionalNodes::getRLeja(max_level); }else if (rule == rule_rlejashifted){ nodes = OneDimensionalNodes::getRLejaShifted(max_level); } } coeff.resize((size_t) max_level); coeff[0] = 1.0; for(int i=1; i GridSequence::cacheBasisIntegrals() const{ int max_level = max_levels[0]; for(auto l: max_levels) if (max_level < l) max_level = l; std::vector integ(++max_level, 0.0); // integrals of basis functions int n = 1 + max_level / 2; // number of Gauss-Legendre points needed to integrate the basis functions std::vector lag_x, lag_w; OneDimensionalNodes::getGaussLegendre(n, lag_w, lag_x); for(int i=0; i(num_outputs, num_points, std::vector(values.begin(), values.end())); int num_levels = 1 + *std::max_element(points.begin(), points.end()); // construct matrix of basis values at nodes std::vector vmatrix(num_levels * num_levels, 0); #pragma omp parallel for for(int i=0; i> map; std::vector> job_indexes; MultiIndexManipulations::resortIndexes(points, map, job_indexes); for(int d=num_dimensions-1; d>=0; d--) { #pragma omp parallel for for(int job = 0; job < static_cast(job_indexes[d].size() - 1); job++) { const int offset = job_indexes[d][job] * num_levels + job_indexes[d][job]; for(int i=job_indexes[d][job]+1; i void GridSequence::applyTransformationTransposed(double weights[]) const{ // mode 0: applies the transposed linear operator for interpolation and quadrature. // mode 1: applies the transposed linear operator for differentiation. const MultiIndexSet& work = (points.empty()) ? needed : points; int num_points = work.getNumIndexes(); std::vector level = MultiIndexManipulations::computeLevels(work); int top_level = *std::max_element(level.begin(), level.end()); Data2D parents = MultiIndexManipulations::computeDAGup(work); std::vector monkey_count(top_level + 1); std::vector monkey_tail(top_level + 1); std::vector used(num_points); for(int l=top_level; l>0; l--){ for(int i=0; i; GridSequence(AccelerationContext const *acc, const GridSequence *seq, int ibegin, int iend); GridSequence(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int depth, TypeDepth type, TypeOneDRule crule, const std::vector &anisotropic_weights, const std::vector &level_limits); GridSequence(AccelerationContext const *acc, int cnum_dimensions, int depth, TypeDepth type, TypeOneDRule crule, const std::vector &anisotropic_weights, const std::vector &level_limits); GridSequence(AccelerationContext const *acc, MultiIndexSet &&pset, int cnum_outputs, TypeOneDRule crule); ~GridSequence() = default; bool isSequence() const override{ return true; } void write(std::ostream &os, bool iomode) const override{ if (iomode == mode_ascii) write(os); else write(os); } template void write(std::ostream &os) const; void updateGrid(int depth, TypeDepth type, const std::vector &anisotropic_weights, const std::vector &level_limits); TypeOneDRule getRule() const override{ return rule; } void getLoadedPoints(double *x) const override; void getNeededPoints(double *x) const override; void getPoints(double *x) const override; // returns the loaded points unless no points are loaded, then returns the needed points void getQuadratureWeights(double weights[]) const override; void getInterpolationWeights(const double x[], double weights[]) const override; void getDifferentiationWeights(const double x[], double weights[]) const override; void loadNeededValues(const double *vals) override; void evaluate(const double x[], double y[]) const override; void integrate(double q[], double *conformal_correction) const override; void differentiate(const double x[], double jacobian[]) const override; void evaluateBatch(const double x[], int num_x, double y[]) const override; void evaluateBatchGPU(const double gpu_x[], int cpu_num_x, double gpy_y[]) const override; void evaluateHierarchicalFunctionsGPU(const double x[], int num_x, double y[]) const override; void evaluateBatchGPU(const float gpu_x[], int cpu_num_x, float gpy_y[]) const override; template void evaluateBatchGPUtempl(const T gpu_x[], int cpu_num_x, T gpy_y[]) const; void evaluateHierarchicalFunctionsGPU(const float gpu_x[], int num_x, float gpu_y[]) const override; void evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const override; void estimateAnisotropicCoefficients(TypeDepth type, int output, std::vector &weights) const; void setAnisotropicRefinement(TypeDepth type, int min_growth, int output, const std::vector &level_limits); void setSurplusRefinement(double tolerance, int output, const std::vector &level_limits); void clearRefinement() override; void mergeRefinement() override; void beginConstruction() override; void writeConstructionData(std::ostream &ofs, bool) const override; void readConstructionData(std::istream &ifs, bool) override; std::vector getCandidateConstructionPoints(TypeDepth type, const std::vector &weights, const std::vector &level_limits); std::vector getCandidateConstructionPoints(TypeDepth type, int output, const std::vector &level_limits); std::vector getCandidateConstructionPoints(std::function getTensorWeight, const std::vector &level_limits); void loadConstructedPoint(const double x[], const std::vector &y) override; void loadConstructedPoint(const double x[], int numx, const double y[]) override; void finishConstruction() override; void setHierarchicalCoefficients(const double c[]) override; void integrateHierarchicalFunctions(double integrals[]) const override; std::vector getPolynomialSpace(bool interpolation) const; const double* getSurpluses() const; void updateAccelerationData(AccelerationContext::ChangeType change) const override; double getNode(int i) const{ return nodes[i]; } protected: void evalHierarchicalFunctions(const double x[], double fvalues[]) const; //! \brief Cache the nodes and polynomial coefficients, cache is determined by the largest index in \b points and \b needed, or \b num_external (pass zero if not using dy-construction). void prepareSequence(int num_external); std::vector cacheBasisIntegrals() const; template std::vector> cacheBasisValues(const T x[]) const{ std::vector> cache(num_dimensions); for(int j=0; j std::vector> cacheBasisDerivatives(const T x[]) const { std::vector> cache(num_dimensions); for(int j=0; j 0) cache[j][1] = 1.0 / coeff[1]; for(int i=2; i <= max_levels[j]; i++){ s *= (this_x - nodes[i-1]); b *= (this_x - nodes[i-2]); s += b; cache[j][i] = s / coeff[i]; } } return cache; } std::vector getMultiIndex(const double x[]); void expandGrid(const std::vector &point, const std::vector &values, const std::vector &surplus); void loadConstructedPoints(); void recomputeSurpluses(); template void applyTransformationTransposed(double weights[]) const; double evalBasis(const int f[], const int p[]) const; // evaluate function corresponding to f at p void clearGpuNodes() const; void clearGpuSurpluses() const; private: TypeOneDRule rule; Data2D surpluses; std::vector nodes; std::vector coeff; std::vector max_levels; std::unique_ptr dynamic_values; // specialize below for the float case std::unique_ptr>& getGpuCacheOverload(double) const{ return gpu_cache; } std::unique_ptr>& getGpuCacheOverload(float) const{ return gpu_cachef; } template std::unique_ptr>& getGpuCache() const{ return getGpuCacheOverload(static_cast(0.0)); } template void loadGpuNodes() const{ auto& ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (!ccache->num_nodes.empty()) return; ccache->nodes.load(acceleration, nodes); ccache->coeff.load(acceleration, coeff); std::vector num_nodes(num_dimensions); std::transform(max_levels.begin(), max_levels.end(), num_nodes.begin(), [](int i)->int{ return i+1; }); ccache->num_nodes.load(acceleration, num_nodes); const MultiIndexSet *work = (points.empty()) ? &needed : &points; int num_points = work->getNumIndexes(); Data2D transpoints(work->getNumIndexes(), num_dimensions); for(int i=0; igetIndex(i)[j]; } } ccache->points.load(acceleration, transpoints.begin(), transpoints.end()); } template void loadGpuSurpluses() const{ auto& ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (ccache->surpluses.empty()) ccache->surpluses.load(acceleration, surpluses.begin(), surpluses.end()); } mutable std::unique_ptr> gpu_cache; mutable std::unique_ptr> gpu_cachef; }; // Old version reader template<> struct GridReaderVersion5{ template static std::unique_ptr read(AccelerationContext const *acc, std::istream &is){ std::unique_ptr grid = Utils::make_unique(acc); grid->num_dimensions = IO::readNumber(is); grid->num_outputs = IO::readNumber(is); grid->rule = IO::readRule(is); if (IO::readFlag(is)) grid->points = MultiIndexSet(is, iomode()); if (IO::readFlag(is)) grid->needed = MultiIndexSet(is, iomode()); if (IO::readFlag(is)) grid->surpluses = IO::readData2D(is, grid->num_outputs, grid->points.getNumIndexes()); if (grid->num_outputs > 0) grid->values = StorageSet(is, iomode()); grid->prepareSequence(0); return grid; } }; #endif // __TASMANIAN_DOXYGEN_SKIP } #endif TASMANIAN-8.1/SparseGrids/tsgGridWavelet.cpp000066400000000000000000001306741470551176200206050ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_WAVELET_CPP #define __TASMANIAN_SPARSE_GRID_WAVELET_CPP #include "tsgGridWavelet.hpp" #include "tsgTPLWrappers.hpp" namespace TasGrid{ template void GridWavelet::write(std::ostream &os) const{ if (iomode == mode_ascii){ os << std::scientific; os.precision(17); } IO::writeNumbers(os, num_dimensions, num_outputs, order); IO::writeFlag(!points.empty(), os); if (!points.empty()) points.write(os); if (iomode == mode_ascii){ // backwards compatible: surpluses and needed, or needed and surpluses IO::writeFlag((coefficients.getNumStrips() != 0), os); if (!coefficients.empty()) coefficients.writeVector(os); IO::writeFlag(!needed.empty(), os); if (!needed.empty()) needed.write(os); }else{ IO::writeFlag(!needed.empty(), os); if (!needed.empty()) needed.write(os); IO::writeFlag((coefficients.getNumStrips() != 0), os); if (!coefficients.empty()) coefficients.writeVector(os); } if (num_outputs > 0) values.write(os); } template void GridWavelet::write(std::ostream &) const; template void GridWavelet::write(std::ostream &) const; GridWavelet::GridWavelet(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int depth, int corder, const std::vector &level_limits) : BaseCanonicalGrid(acc, cnum_dimensions, cnum_outputs, MultiIndexSet(), (corder == 1) ? MultiIndexManipulations::generateNestedPoints( MultiIndexManipulations::selectTensors((size_t) cnum_dimensions, depth, type_level, [](int i) -> int{ return i; }, std::vector(), level_limits), [](int l)->int{ return (1 << (l + 1)) + 1; }) : MultiIndexManipulations::generateNestedPoints( MultiIndexManipulations::selectTensors((size_t) cnum_dimensions, depth, type_level, [](int i) -> int{ return i; }, std::vector(), level_limits), [](int l)->int{ return (1 << (l + 2)) + 1; }), StorageSet()), rule1D(corder, 10), order(corder){ if (num_outputs == 0){ points = std::move(needed); needed = MultiIndexSet(); }else{ values.resize(num_outputs, needed.getNumIndexes()); } } GridWavelet::GridWavelet(AccelerationContext const *acc, GridWavelet const *wav, int ibegin, int iend) : BaseCanonicalGrid(acc, *wav, ibegin, iend), rule1D(wav->rule1D), order(wav->order), coefficients((num_outputs == wav->num_outputs) ? wav->coefficients : wav->coefficients.splitData(ibegin, iend)) { if (wav->dynamic_values){ dynamic_values = Utils::make_unique(*wav->dynamic_values); if (num_outputs != wav->num_outputs) dynamic_values->restrictData(ibegin, iend); // handle when copy a subset of the outputs } } GridWavelet::GridWavelet(AccelerationContext const *acc, MultiIndexSet &&pset, int cnum_outputs, int corder, Data2D &&vals) : BaseCanonicalGrid(acc, static_cast(pset.getNumDimensions()), cnum_outputs, std::forward(pset), MultiIndexSet(), StorageSet()), rule1D(corder, 10), order(corder) { if (num_outputs > 0){ values = StorageSet(num_outputs, points.getNumIndexes(), vals.release()); recomputeCoefficients(); } } void GridWavelet::getLoadedPoints(double *x) const{ int num_points = points.getNumIndexes(); Utils::Wrapper2D split(num_dimensions, x); #pragma omp parallel for schedule(static) for(int i=0; i split(num_dimensions, x); #pragma omp parallel for schedule(static) for(int i=0; i local_weights(num_points); for (int d=0; d(Utils::size_mult(num_all_points, num_outputs), 0.0)); if (points.empty()){ points = std::move(needed); }else{ points += needed; } needed = MultiIndexSet(); coefficients = Data2D(num_outputs, num_all_points); } void GridWavelet::evaluate(const double x[], double y[]) const{ std::fill(y, y + num_outputs, 0.0); int num_points = points.getNumIndexes(); for(int i=0; imode){ case accel_gpu_magma: case accel_gpu_cuda: { acceleration->setDevice(); if ((order != 1) || (num_x == 1)){ // GPU evaluations are available only for order 1 // cannot use GPU to accelerate the evaluation of a single vector evaluateGpuMixed(x, num_x, y); return; } GpuVector gpu_x(acceleration, num_dimensions, num_x, x), gpu_result(acceleration, num_x, num_outputs); evaluateBatchGPU(gpu_x.data(), num_x, gpu_result.data()); gpu_result.unload(acceleration, y); break; } case accel_gpu_cublas: { acceleration->setDevice(); evaluateGpuMixed(x, num_x, y); break; } case accel_cpu_blas: { int num_points = points.getNumIndexes(); Data2D weights(num_points, num_x); evaluateHierarchicalFunctions(x, num_x, weights.getStrip(0)); TasBLAS::denseMultiply(num_outputs, num_x, num_points, 1.0, coefficients.getStrip(0), weights.getStrip(0), 0.0, y); break; } default: { Utils::Wrapper2D xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(num_outputs, y); #pragma omp parallel for for(int i=0; i(); Data2D weights(points.getNumIndexes(), num_x); evaluateHierarchicalFunctions(x, num_x, weights.getStrip(0)); TasGpu::denseMultiplyMixed(acceleration, num_outputs, num_x, points.getNumIndexes(), 1.0, gpu_cache->coefficients, weights.data(), 0.0, y); } template void GridWavelet::evaluateBatchGPUtempl(const T *gpu_x, int cpu_num_x, T gpu_y[]) const{ if (order != 1) throw std::runtime_error("ERROR: GPU evaluations are available only for wavelet grids with order 1"); loadGpuCoefficients(); int num_points = points.getNumIndexes(); GpuVector gpu_basis(acceleration, cpu_num_x, num_points); evaluateHierarchicalFunctionsGPU(gpu_x, cpu_num_x, gpu_basis.data()); TasGpu::denseMultiply(acceleration, num_outputs, cpu_num_x, num_points, 1.0, getGpuCache()->coefficients, gpu_basis, 0.0, gpu_y); } void GridWavelet::evaluateBatchGPU(const double *gpu_x, int cpu_num_x, double gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridWavelet::evaluateBatchGPU(const float *gpu_x, int cpu_num_x, float gpu_y[]) const{ evaluateBatchGPUtempl(gpu_x, cpu_num_x, gpu_y); } void GridWavelet::evaluateHierarchicalFunctionsGPU(const double gpu_x[], int cpu_num_x, double *gpu_y) const{ loadGpuBasis(); TasGpu::devalpwpoly(acceleration, order, rule_wavelet, num_dimensions, cpu_num_x, getNumPoints(), gpu_x, gpu_cache->nodes.data(), gpu_cache->support.data(), gpu_y); } void GridWavelet::evaluateHierarchicalFunctionsGPU(const float gpu_x[], int cpu_num_x, float *gpu_y) const{ loadGpuBasis(); TasGpu::devalpwpoly(acceleration, order, rule_wavelet, num_dimensions, cpu_num_x, getNumPoints(), gpu_x, gpu_cachef->nodes.data(), gpu_cachef->support.data(), gpu_y); } template void GridWavelet::loadGpuBasis() const{ auto &ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (!ccache->nodes.empty()) return; const MultiIndexSet &work = (points.empty()) ? needed : points; Data2D cpu_scale(num_dimensions, work.getNumIndexes()); Data2D cpu_shift(num_dimensions, work.getNumIndexes()); for(int i=0; inodes.load(acceleration, cpu_scale.begin(), cpu_scale.end()); ccache->support.load(acceleration, cpu_shift.begin(), cpu_shift.end()); } void GridWavelet::clearGpuBasis() const{ if (gpu_cache) gpu_cache->clearNodes(); if (gpu_cachef) gpu_cachef->clearNodes(); } template void GridWavelet::loadGpuCoefficients() const{ auto &ccache = getGpuCache(); if (!ccache) ccache = Utils::make_unique>(); if (ccache->coefficients.empty()) ccache->coefficients.load(acceleration, coefficients.begin(), coefficients.end()); } void GridWavelet::clearGpuCoefficients() const{ if (gpu_cache) gpu_cache->coefficients.clear(); if (gpu_cachef) gpu_cachef->coefficients.clear(); } void GridWavelet::integrate(double q[], double *conformal_correction) const{ int num_points = points.getNumIndexes(); std::fill_n(q, num_outputs, 0.0); if (conformal_correction == 0){ for(int i=0; i w(num_points); getQuadratureWeights(w.data()); for(int i=0; i basis_jacobian(num_dimensions); for(int i=0; i(p[i], x[i]); if (v == 0.0){ break; }; // MIRO: reduce the expensive wavelet evaluations } return v; } double GridWavelet::evalIntegral(const int p[]) const{ // For a given node p, evaluate the integral of the associated wavelet. double v = 1.0; for(int i = 0; i < num_dimensions; i++){ v *= rule1D.getWeight(p[i]); if (v == 0.0){ break; }; // MIRO: reduce the expensive wavelet evaluations } return v; } void GridWavelet::evalDiffBasis(const int p[], const double x[], double jacobian[]) const { // Evaluates the derivative of the wavelet basis given at point p at the coordinates given by x. // The derivative function of a symmetric function will be antisymmetric across the origin for every x != 0.0. std::vector value_cache(num_dimensions); for(int i=0; i(p[i], x[i]); jacobian[i] = rule1D.eval<1>(p[i], x[i]); } double t = 1.0; for(int i=1; i=0; i--){ t *= value_cache[i+1]; jacobian[i] *= t; } } void GridWavelet::buildInterpolationMatrix() const{ // updated code, using better parallelism // Wavelets don't have a nice rule of support to use monkeys and graphs (or I cannot find the support rule) MultiIndexSet const &work = (points.empty()) ? needed : points; int num_points = work.getNumIndexes(); if (order == 1 and TasSparse::WaveletBasisMatrix::useDense(acceleration, num_points) and acceleration->useKernels()){ // using the GPU algorithm acceleration->setDevice(); std::vector pnts(Utils::size_mult(num_dimensions, num_points)); getPoints(pnts.data()); GpuVector gpu_pnts(acceleration, pnts); GpuVector gpu_basis(acceleration, num_points, num_points); evaluateHierarchicalFunctionsGPU(gpu_pnts.data(), num_points, gpu_basis.data()); inter_matrix = TasSparse::WaveletBasisMatrix(acceleration, num_points, std::move(gpu_basis)); return; } int num_chunk = 32; int num_blocks = num_points / num_chunk + ((num_points % num_chunk == 0) ? 0 : 1); std::vector> indx(num_blocks); std::vector> vals(num_blocks); std::vector pntr(num_points); #pragma omp parallel for for(int b=0; b xi = MultiIndexManipulations::getIndexesToNodes(work.getIndex(i), (size_t) num_dimensions, rule1D); // loop over the basis functions to see if supported int numpntr = 0; for(int wi=0; wi(w[j], xi[j]); if (v == 0.0) break; // evaluating the wavelets is expensive, stop if any one of them is zero } if(v != 0.0){ // testing != is safe since it can only happen in multiplication by 0.0 indx[b].push_back(wi); vals[b].push_back(v); numpntr++; } } pntr[i] = numpntr; } } inter_matrix = TasSparse::WaveletBasisMatrix(acceleration, pntr, indx, vals); } void GridWavelet::recomputeCoefficients(){ // Recalculates the coefficients to interpolate the values in points. // Make sure buildInterpolationMatrix has been called since the list was updated. int num_points = points.getNumIndexes(); coefficients = Data2D(num_outputs, num_points, std::vector(values.begin(), values.end())); if (inter_matrix.getNumRows() != num_points) buildInterpolationMatrix(); inter_matrix.invert(acceleration, num_outputs, coefficients.data()); // do not keep the matrix if working with internal interpolation, don't want to hog GPU RAM if (num_outputs > 0) inter_matrix = TasSparse::WaveletBasisMatrix(); } std::vector GridWavelet::getNormalization() const{ std::vector norm(num_outputs, 0.0); for(int i=0; i GridWavelet::buildUpdateMap(double tolerance, TypeRefinement criteria, int output) const{ int num_points = points.getNumIndexes(); Data2D pmap(num_dimensions, num_points, std::vector(Utils::size_mult(num_dimensions, num_points), (tolerance == 0.0) ? 1 : 0) // tolerance 0 means "refine everything" ); if (tolerance == 0.0) return pmap; std::vector norm = getNormalization(); if ((criteria == refine_classic) || (criteria == refine_parents_first)){ // classic refinement #pragma omp parallel for for(int i=0; i tolerance)) small = false; } }else{ small = !((std::abs(s[output]) / norm[output]) > tolerance); } if (!small){ int *p = pmap.getStrip(i); std::fill(p, p + num_dimensions, 1); } } }else{ HierarchyManipulations::SplitDirections split(points); for(int s=0; s vals(active_outputs, nump); Data2D indexes(num_dimensions, nump); for(int i=0; i tolerance) && ((std::abs(coeff[k]) / norm[k]) > tolerance)) small = false; } }else{ if (((std::abs(soeff[output]) / norm[output]) > tolerance) && ((std::abs(coeff[0]) / norm[output]) > tolerance)) small = false; } pmap.getStrip(pnts[i])[d] = (small) ? 0 : 1; } } } return pmap; } bool GridWavelet::addParent(const int point[], int direction, Data2D &destination) const{ std::vector dad(point, point + num_dimensions); bool added = false; dad[direction] = rule1D.getParent(point[direction]); if (dad[direction] == -2){ for(int c=0; c= 0){ if (points.missing(dad)){ destination.appendStrip(dad); added = true; } } return added; } void GridWavelet::addChild(const int point[], int direction, Data2D &destination) const{ std::vector kid(point, point + num_dimensions); int L, R; rule1D.getChildren(point[direction], L, R); kid[direction] = L; if ((kid[direction] != -1) && points.missing(kid)){ destination.appendStrip(kid); } kid[direction] = R; if ((kid[direction] != -1) && points.missing(kid)){ destination.appendStrip(kid); } } void GridWavelet::addChildLimited(const int point[], int direction, const std::vector &level_limits, Data2D &destination) const{ std::vector kid(point, point + num_dimensions); int L, R; rule1D.getChildren(point[direction], L, R); kid[direction] = L; if ((kid[direction] != -1) && ((level_limits[direction] == -1) || (rule1D.getLevel(L) <= level_limits[direction])) && points.missing(kid)){ destination.appendStrip(kid); } kid[direction] = R; if ((kid[direction] != -1) && ((level_limits[direction] == -1) || (rule1D.getLevel(R) <= level_limits[direction])) && points.missing(kid)){ destination.appendStrip(kid); } } void GridWavelet::clearRefinement(){ needed = MultiIndexSet(); } const double* GridWavelet::getSurpluses() const{ return coefficients.getStrip(0); } void GridWavelet::beginConstruction(){ dynamic_values = Utils::make_unique(); if (points.empty()){ dynamic_values->initial_points = std::move(needed); needed = MultiIndexSet(); } } void GridWavelet::writeConstructionData(std::ostream &os, bool iomode) const{ if (iomode == mode_ascii) dynamic_values->write(os); else dynamic_values->write(os); } void GridWavelet::readConstructionData(std::istream &is, bool iomode){ if (iomode == mode_ascii) dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_ascii_type()); else dynamic_values = Utils::make_unique(is, num_dimensions, num_outputs, IO::mode_binary_type()); } namespace WaveManipulations{ inline void touchAllImmediateRelatives(std::vector &&point, MultiIndexSet const &mset, RuleWavelet const &rule, std::function apply){ for(auto &v : point){ int save = v; // replace one by one each index of p with either parent or kid // check the parents v = rule.getParent(save); if (v == -2){ // include everything on level 0 for(v = 0; v < rule.getNumPoints(0); v++){ int parent_index = mset.getSlot(point); if (parent_index > -1) apply(parent_index); } }else if (v > -1){ int parent_index = mset.getSlot(point); if (parent_index > -1) apply(parent_index); } int kid1, kid2; rule.getChildren(save, kid1, kid2); std::vector kids = {kid1, kid2}; for(auto k : kids){ if (k > -1){ v = k; int parent_index = mset.getSlot(point); if (parent_index > -1) apply(parent_index); } } v = save; // restore the original index for the next iteration } } std::vector computeLevels(MultiIndexSet const &mset, RuleWavelet const &rule){ size_t num_dimensions = mset.getNumDimensions(); int num_points = mset.getNumIndexes(); std::vector level((size_t) num_points); #pragma omp parallel for schedule(static) for(int i=0; i(num_dimensions, rule.getNumPoints(0))); MultiIndexSet result; // keep track of the cumulative result MultiIndexSet total = current; // forms a working copy of the entire merged graph // do not consider the points already included in total, complexity is level_zero.getNumIndexes() if (!total.empty()) level_zero = level_zero - total; if (level_zero.getNumIndexes() > 0){ // level zero nodes are missing from current Data2D roots(num_dimensions, 0); for(int i=0; i p = level_zero.copyIndex(i); if (!candidates.missing(p)) roots.appendStrip(p); } result = MultiIndexSet(roots); total += result; } if (total.empty()) return MultiIndexSet(); // current was empty and no roots could be added Data2D update; do{ update = Data2D(num_dimensions, 0); for(int i=0; i relative = total.copyIndex(i); for(auto &r : relative){ int k = r; // save the value std::vector possible_relatives; possible_relatives.reserve((size_t) rule.getNumPoints(0) + 2); int kid1, kid2; rule.getChildren(k, kid1, kid2); possible_relatives.push_back(kid1); possible_relatives.push_back(kid2); int parent = rule.getParent(k); if (parent == -2){ for(int p=0; p -1){ r = p; if (!candidates.missing(relative) && total.missing(relative)) update.appendStrip(relative); } } r = k; } } if (update.getNumStrips() > 0){ MultiIndexSet update_set(update); result += update_set; total += update_set; } }while(update.getNumStrips() > 0); return result; } } std::vector GridWavelet::getCandidateConstructionPoints(double tolerance, TypeRefinement criteria, int output, std::vector const &level_limits){ MultiIndexSet refine_candidates = getRefinementCanidates(tolerance, criteria, output, level_limits); MultiIndexSet new_points = (dynamic_values->initial_points.empty()) ? std::move(refine_candidates) : refine_candidates - dynamic_values->initial_points; // compute the weights for the new_points points std::vector norm = getNormalization(); auto getDominantSurplus = [&](int i)-> double{ double dominant = 0.0; const double *s = coefficients.getStrip(i); if (output == -1){ for(int k=0; k refine_weights(new_points.getNumIndexes()); #pragma omp parallel for for(int i=0; ivoid{ weight = std::max(weight, getDominantSurplus(relative)); }); refine_weights[i] = weight; // those will be inverted } // if using stable refinement, ensure the weight of the parents is never less than the children if (!new_points.empty() && ((criteria == refine_parents_first) || (criteria == refine_fds))){ auto rlevels = WaveManipulations::computeLevels(new_points, rule1D); auto split = HierarchyManipulations::splitByLevels(new_points, rlevels); for(auto is = split.rbegin(); is != split.rend(); is++){ for(int i=0; igetNumStrips(); i++){ std::vector parent(is->getStrip(i), is->getStrip(i) + num_dimensions); double correction = refine_weights[new_points.getSlot(parent)]; // will never be missing for(auto &p : parent){ int r = p; p = rule1D.getParent(r); if (p > -1){ int ip = new_points.getSlot(parent); // if parent is among the refined if (ip != -1) refine_weights[ip] += correction; }else if (p == -2){ for(p = 0; p weight[j] auto rlevels = WaveManipulations::computeLevels(new_points, rule1D); auto split = HierarchyManipulations::splitByLevels(new_points, rlevels); double max_weight = 0.0; for(auto is = split.rbegin(); is != split.rend(); is++){ // loop backwards in levels double correction = max_weight; for(int i=0; igetNumStrips(); i++){ int idx = new_points.getSlot(std::vector(is->getStrip(i), is->getStrip(i) + num_dimensions)); refine_weights[idx] += correction; max_weight = std::max(max_weight, refine_weights[idx]); } } } // compute the weights for the initial points std::vector initial_levels = WaveManipulations::computeLevels(dynamic_values->initial_points, rule1D); std::forward_list weighted_points; for(int i=0; iinitial_points.getNumIndexes(); i++) weighted_points.push_front({dynamic_values->initial_points.copyIndex(i), {-1.0 / ((double) initial_levels[i])}}); for(int i=0; ibool{ return (a.value[0] < b.value[0]); }); return listToNodes(weighted_points, num_dimensions, rule1D); } std::vector GridWavelet::getMultiIndex(const double x[]){ std::vector p(num_dimensions); // convert x to p, maybe expensive for(int j=0; j Maths::num_tol) i++; p[j] = i; } return p; } void GridWavelet::loadConstructedPoint(const double x[], const std::vector &y){ loadConstructedPoint(x, 1, y.data()); } void GridWavelet::loadConstructedPoint(const double x[], int numx, const double y[]){ Utils::Wrapper2D wrapx(num_dimensions, x); std::vector> pnts(numx); #pragma omp parallel for for(int i=0; iinitial_points.empty()){ Data2D combined_pnts(num_dimensions, numx); for(int i=0; iinitial_points = dynamic_values->initial_points - combined_pnts; } Utils::Wrapper2D wrapy(num_outputs, y); for(int i=0; idata.push_front({std::move(pnts[i]), std::vector(wrapy.getStrip(i), wrapy.getStrip(i) + num_outputs)}); Data2D candidates(num_dimensions, (int) std::distance(dynamic_values->data.begin(), dynamic_values->data.end())); for(struct{ int i; std::forward_list::iterator d; } p = {0, dynamic_values->data.begin()}; p.d != dynamic_values->data.end(); p.i++, p.d++){ std::copy_n(p.d->point.begin(), num_dimensions, candidates.getIStrip(p.i)); } auto new_points = WaveManipulations::getLargestConnected(points, MultiIndexSet(candidates), rule1D); if (new_points.empty()) return; clearGpuBasis(); // the points will change, clear the cache clearGpuCoefficients(); auto vals = dynamic_values->extractValues(new_points); if (points.empty()){ points = std::move(new_points); values.setValues(std::move(vals)); }else{ values.addValues(points, new_points, vals.data()); points += new_points; } recomputeCoefficients(); // costly, but the only option under the circumstances } void GridWavelet::finishConstruction(){ dynamic_values.reset(); } void GridWavelet::evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const{ const MultiIndexSet &work = (points.empty()) ? needed : points; int num_points = work.getNumIndexes(); Utils::Wrapper2D xwrap(num_dimensions, x); Utils::Wrapper2D ywrap(num_points, y); #pragma omp parallel for for(int i=0; i(p[k], this_x[k]); if (v == 0.0){ break; }; // MIRO: evaluating the wavelets is expensive, stop if any one of them is zero } this_y[j] = v; } } } std::vector GridWavelet::getSupport() const{ MultiIndexSet const &work = (points.empty()) ? needed : points; std::vector support(Utils::size_mult(work.getNumIndexes(), work.getNumDimensions())); std::transform(work.begin(), work.end(), support.begin(), [&](int p)->double{ return rule1D.getSupport(p); }); return support; } void GridWavelet::setHierarchicalCoefficients(const double c[]){ clearGpuCoefficients(); if (!points.empty()){ clearRefinement(); }else{ points = std::move(needed); needed = MultiIndexSet(); } auto num_points = points.getNumIndexes(); coefficients = Data2D(num_outputs, num_points, std::vector(c, c + Utils::size_mult(num_outputs, num_points))); std::vector y(Utils::size_mult(num_outputs, num_points)); std::vector x(Utils::size_mult(num_dimensions, num_points)); getPoints(x.data()); evaluateBatch(x.data(), points.getNumIndexes(), y.data()); values = StorageSet(num_outputs, num_points, std::move(y)); } void GridWavelet::integrateHierarchicalFunctions(double integrals[]) const{ const MultiIndexSet& work = (points.empty()) ? needed : points; int const num_points = work.getNumIndexes(); for(int i=0; i &level_limits) const{ Data2D pmap = buildUpdateMap(tolerance, criteria, output); bool useParents = (criteria == refine_fds) || (criteria == refine_parents_first); Data2D refined(num_dimensions, 0); int num_points = points.getNumIndexes(); #ifdef _OPENMP #pragma omp parallel { Data2D lrefined(num_dimensions, 0); if (level_limits.empty()){ #pragma omp for for(int i=0; i 0) ? MultiIndexSet(refined) : MultiIndexSet(); if (criteria == refine_stable){ // complete needed to a lower set size_t num_added = 1; // set to 1 to start the loop while(num_added > 0){ Data2D addons(num_dimensions, 0); int num_needed = result.getNumIndexes(); for(int i=0; i parent = result.copyIndex(i); for(auto &p : parent){ int r = p; p = rule1D.getParent(r); if ((p > -1) && result.missing(parent) && points.missing(parent)) addons.appendStrip(parent); if (p == -2){ // all parents on level 0 for(int j=0; j 0) result += addons; } } return result; } void GridWavelet::setSurplusRefinement(double tolerance, TypeRefinement criteria, int output, const std::vector &level_limits){ clearRefinement(); needed = getRefinementCanidates(tolerance, criteria, output, level_limits); } void GridWavelet::updateAccelerationData(AccelerationContext::ChangeType change) const{ switch(change){ case AccelerationContext::change_gpu_device: gpu_cache.reset(); gpu_cachef.reset(); if (inter_matrix.getNumRows() > 0) inter_matrix = TasSparse::WaveletBasisMatrix(); break; case AccelerationContext::change_sparse_dense: if ((acceleration->algorithm_select == AccelerationContext::algorithm_dense and inter_matrix.isSparse()) or (acceleration->algorithm_select == AccelerationContext::algorithm_sparse and inter_matrix.isDense())) inter_matrix = TasSparse::WaveletBasisMatrix(); break; default: break; } } } #endif TASMANIAN-8.1/SparseGrids/tsgGridWavelet.hpp000066400000000000000000000220731470551176200206030ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_WAVELET_HPP #define __TASMANIAN_SPARSE_GRID_WAVELET_HPP #include "tsgRuleWavelet.hpp" namespace TasGrid{ #ifndef __TASMANIAN_DOXYGEN_SKIP class GridWavelet : public BaseCanonicalGrid{ public: GridWavelet(AccelerationContext const *acc) : BaseCanonicalGrid(acc), rule1D(1, 10), order(1){} friend struct GridReaderVersion5; GridWavelet(AccelerationContext const *acc, const GridWavelet *wav, int ibegin, int iend); GridWavelet(AccelerationContext const *acc, int cnum_dimensions, int cnum_outputs, int depth, int corder, const std::vector &level_limits); GridWavelet(AccelerationContext const *acc, MultiIndexSet &&pset, int cnum_outputs, int corder, Data2D &&vals); ~GridWavelet() = default; bool isWavelet() const override{ return true; } void write(std::ostream &os, bool iomode) const override{ if (iomode == mode_ascii) write(os); else write(os); } template void write(std::ostream &os) const; TypeOneDRule getRule() const override{ return rule_wavelet; } int getOrder() const{ return order; } void getLoadedPoints(double *x) const override; void getNeededPoints(double *x) const override; void getPoints(double *x) const override; // returns the loaded points unless no points are loaded, then returns the needed points void getQuadratureWeights(double weights[]) const override; void getInterpolationWeights(const double x[], double weights[]) const override; void getDifferentiationWeights(const double x[], double weights[]) const override; void loadNeededValues(const double *vals) override; void evaluate(const double x[], double y[]) const override; void integrate(double q[], double *conformal_correction) const override; void differentiate(const double x[], double jacobian[]) const override; void evaluateBatch(const double x[], int num_x, double y[]) const override; void evaluateGpuMixed(const double*, int, double[]) const; void evaluateBatchGPU(const double*, int, double[]) const override; void evaluateBatchGPU(const float*, int, float[]) const override; template void evaluateBatchGPUtempl(const T*, int, T[]) const; void evaluateHierarchicalFunctionsGPU(const double gpu_x[], int cpu_num_x, double *gpu_y) const override; void evaluateHierarchicalFunctionsGPU(const float gpu_x[], int cpu_num_x, float *gpu_y) const override; void setSurplusRefinement(double tolerance, TypeRefinement criteria, int output, const std::vector &level_limits); void clearRefinement() override; void mergeRefinement() override; void beginConstruction() override; void writeConstructionData(std::ostream&, bool) const override; void readConstructionData(std::istream&, bool) override; std::vector getCandidateConstructionPoints(double tolerance, TypeRefinement criteria, int output, std::vector const &level_limits); void loadConstructedPoint(const double[], const std::vector &) override; void loadConstructedPoint(const double[], int, const double[]) override; void finishConstruction() override; void evaluateHierarchicalFunctions(const double x[], int num_x, double y[]) const override; std::vector getSupport() const override; void setHierarchicalCoefficients(const double c[]) override; void integrateHierarchicalFunctions(double integrals[]) const override; const double* getSurpluses() const; void updateAccelerationData(AccelerationContext::ChangeType change) const override; protected: double evalBasis(const int p[], const double x[]) const; void buildInterpolationMatrix() const; void recomputeCoefficients(); void solveTransposed(double w[]) const; double evalIntegral(const int p[]) const; void evalDiffBasis(const int p[], const double x[], double jacobian[]) const; std::vector getNormalization() const; std::vector getMultiIndex(const double x[]); Data2D buildUpdateMap(double tolerance, TypeRefinement criteria, int output) const; MultiIndexSet getRefinementCanidates(double tolerance, TypeRefinement criteria, int output, const std::vector &level_limits) const; bool addParent(const int point[], int direction, Data2D &destination) const; void addChild(const int point[], int direction, Data2D &destination) const; void addChildLimited(const int point[], int direction, const std::vector &level_limits, Data2D &destination) const; void clearGpuCoefficients() const; void clearGpuBasis() const; private: RuleWavelet rule1D; int order; Data2D coefficients; // a.k.a., surpluses mutable TasSparse::WaveletBasisMatrix inter_matrix; std::unique_ptr dynamic_values; std::unique_ptr>& getGpuCacheOverload(double) const{ return gpu_cache; } std::unique_ptr>& getGpuCacheOverload(float) const{ return gpu_cachef; } template std::unique_ptr>& getGpuCache() const{ return getGpuCacheOverload(static_cast(0.0)); } template void loadGpuCoefficients() const; template void loadGpuBasis() const; mutable std::unique_ptr> gpu_cache; mutable std::unique_ptr> gpu_cachef; }; // Old version reader template<> struct GridReaderVersion5{ template static std::unique_ptr read(AccelerationContext const *acc, std::istream &is){ std::unique_ptr grid = Utils::make_unique(acc); grid->num_dimensions = IO::readNumber(is); grid->num_outputs = IO::readNumber(is); grid->order = IO::readNumber(is); grid->rule1D.updateOrder(grid->order); if (IO::readFlag(is)) grid->points = MultiIndexSet(is, iomode()); if (std::is_same::value){ // backwards compatible: surpluses and needed, or needed and surpluses if (IO::readFlag(is)) grid->coefficients = IO::readData2D(is, grid->num_outputs, grid->points.getNumIndexes()); if (IO::readFlag(is)) grid->needed = MultiIndexSet(is, iomode()); }else{ if (IO::readFlag(is)) grid->needed = MultiIndexSet(is, iomode()); if (IO::readFlag(is)) grid->coefficients = IO::readData2D(is, grid->num_outputs, grid->points.getNumIndexes()); } if (grid->num_outputs > 0) grid->values = StorageSet(is, iomode()); grid->buildInterpolationMatrix(); return grid; } }; #endif // __TASMANIAN_DOXYGEN_SKIP } #endif TASMANIAN-8.1/SparseGrids/tsgHardCodedTabulatedRules.cpp000066400000000000000000001425371470551176200230470ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_HARDCODED_RULES_CPP #define __TASMANIAN_SPARSE_HARDCODED_RULES_CPP #include "tsgHardCodedTabulatedRules.hpp" namespace TasGrid{ TableGaussPatterson::TableGaussPatterson(){ weights_offsets.resize(9); weights_offsets[0] = 0; for(int l=0; l<8; l++){ weights_offsets[l+1] = weights_offsets[l] + OneDimensionalMeta::getNumPoints(l, rule_gausspatterson); } loadNodes(); loadWeights(); } std::vector TableGaussPatterson::getNodes(int level) const{ int num_points = OneDimensionalMeta::getNumPoints(level, rule_gausspatterson); std::vector x(nodes.begin(), nodes.begin() + num_points); return x; } double TableGaussPatterson::getWeight(int level, int point) const{ return weights[weights_offsets[level] + point]; } void TableGaussPatterson::loadNodes(){ nodes = {0.000000000000000000000, -0.774596669241483377036, 0.774596669241483377036, -0.960491268708020283423, -0.434243749346802558002, 0.434243749346802558002, 0.960491268708020283423, -0.993831963212755022209, -0.888459232872256998890, -0.621102946737226402941, -0.223386686428966881628, 0.223386686428966881628, 0.621102946737226402941, 0.888459232872256998890, 0.993831963212755022209, -0.999098124967667597662, -0.981531149553740106867, -0.929654857429740056670, -0.836725938168868735503, -0.702496206491527078610, -0.531319743644375623972, -0.331135393257976833093, -0.112488943133186625746, 0.112488943133186625746, 0.331135393257976833093, 0.531319743644375623972, 0.702496206491527078610, 0.836725938168868735503, 0.929654857429740056670, 0.981531149553740106867, 0.999098124967667597662, -0.999872888120357611938, -0.997206259372221959076, -0.988684757547429479939, -0.972182874748581796578, -0.946342858373402905148, -0.910371156957004292498, -0.863907938193690477146, -0.806940531950217611856, -0.739756044352694758677, -0.662909660024780595461, -0.577195710052045814844, -0.483618026945841027562, -0.383359324198730346916, -0.277749822021824315065, -0.168235251552207464982, -0.056344313046592789972, 0.056344313046592789972, 0.168235251552207464982, 0.277749822021824315065, 0.383359324198730346916, 0.483618026945841027562, 0.577195710052045814844, 0.662909660024780595461, 0.739756044352694758677, 0.806940531950217611856, 0.863907938193690477146, 0.910371156957004292498, 0.946342858373402905148, 0.972182874748581796578, 0.988684757547429479939, 0.997206259372221959076, 0.999872888120357611938, -0.999982430354891598580, -0.999598799671910683252, -0.998316635318407392531, -0.995724104698407188509, -0.991495721178106132399, -0.985371499598520371114, -0.977141514639705714156, -0.966637851558416567092, -0.953730006425761136415, -0.938320397779592883655, -0.920340025470012420730, -0.899744899776940036639, -0.876513414484705269742, -0.850644494768350279758, -0.822156254364980407373, -0.791084933799848361435, -0.757483966380513637926, -0.721423085370098915485, -0.682987431091079228087, -0.642276642509759513774, -0.599403930242242892974, -0.554495132631932548866, -0.507687757533716602155, -0.459130011989832332874, -0.408979821229888672409, -0.357403837831532152376, -0.304576441556714043335, -0.250678730303483176613, -0.195897502711100153915, -0.140424233152560174594, -0.0844540400837108837102, -0.0281846489497456943394, 0.0281846489497456943394, 0.0844540400837108837102, 0.140424233152560174594, 0.195897502711100153915, 0.250678730303483176613, 0.304576441556714043335, 0.357403837831532152376, 0.408979821229888672409, 0.459130011989832332874, 0.507687757533716602155, 0.554495132631932548866, 0.599403930242242892974, 0.642276642509759513774, 0.682987431091079228087, 0.721423085370098915485, 0.757483966380513637926, 0.791084933799848361435, 0.822156254364980407373, 0.850644494768350279758, 0.876513414484705269742, 0.899744899776940036639, 0.920340025470012420730, 0.938320397779592883655, 0.953730006425761136415, 0.966637851558416567092, 0.977141514639705714156, 0.985371499598520371114, 0.991495721178106132399, 0.995724104698407188509, 0.998316635318407392531, 0.999598799671910683252, 0.999982430354891598580, -0.999997596379748464620, -0.999943996207054375764, -0.999760490924432047330, -0.999380338025023581928, -0.998745614468095114704, -0.997805354495957274562, -0.996514145914890273849, -0.994831502800621000519, -0.992721344282788615328, -0.990151370400770159181, -0.987092527954034067190, -0.983518657578632728762, -0.979406281670862683806, -0.974734459752402667761, -0.969484659502459231771, -0.963640621569812132521, -0.957188216109860962736, -0.950115297521294876558, -0.942411565191083059813, -0.934068436157725787999, -0.925078932907075652364, -0.915437587155765040644, -0.905140358813261595189, -0.894184568335559022859, -0.882568840247341906842, -0.870293055548113905851, -0.857358310886232156525, -0.843766882672708601038, -0.829522194637401400178, -0.814628787655137413436, -0.799092290960841401800, -0.782919394118283016385, -0.766117819303760090717, -0.748696293616936602823, -0.730664521242181261329, -0.712033155362252034587, -0.692813769779114702895, -0.673018830230418479199, -0.652661665410017496101, -0.631756437711194230414, -0.610318113715186400156, -0.588362434447662541434, -0.565905885423654422623, -0.542965666498311490492, -0.519559661537457021993, -0.495706407918761460170, -0.471425065871658876934, -0.446735387662028473742, -0.421657686626163300056, -0.396212806057615939183, -0.370422087950078230138, -0.344307341599438022777, -0.317890812068476683182, -0.291195148518246681964, -0.264243372410926761945, -0.237058845589829727213, -0.209665238243181194766, -0.182086496759252198246, -0.154346811481378108692, -0.126470584372301966851, -0.0984823965981192020903, -0.0704069760428551790633, -0.0422691647653636032124, -0.0140938864107824626142, 0.0140938864107824626142, 0.0422691647653636032124, 0.0704069760428551790633, 0.0984823965981192020903, 0.126470584372301966851, 0.154346811481378108692, 0.182086496759252198246, 0.209665238243181194766, 0.237058845589829727213, 0.264243372410926761945, 0.291195148518246681964, 0.317890812068476683182, 0.344307341599438022777, 0.370422087950078230138, 0.396212806057615939183, 0.421657686626163300056, 0.446735387662028473742, 0.471425065871658876934, 0.495706407918761460170, 0.519559661537457021993, 0.542965666498311490492, 0.565905885423654422623, 0.588362434447662541434, 0.610318113715186400156, 0.631756437711194230414, 0.652661665410017496101, 0.673018830230418479199, 0.692813769779114702895, 0.712033155362252034587, 0.730664521242181261329, 0.748696293616936602823, 0.766117819303760090717, 0.782919394118283016385, 0.799092290960841401800, 0.814628787655137413436, 0.829522194637401400178, 0.843766882672708601038, 0.857358310886232156525, 0.870293055548113905851, 0.882568840247341906842, 0.894184568335559022859, 0.905140358813261595189, 0.915437587155765040644, 0.925078932907075652364, 0.934068436157725787999, 0.942411565191083059813, 0.950115297521294876558, 0.957188216109860962736, 0.963640621569812132521, 0.969484659502459231771, 0.974734459752402667761, 0.979406281670862683806, 0.983518657578632728762, 0.987092527954034067190, 0.990151370400770159181, 0.992721344282788615328, 0.994831502800621000519, 0.996514145914890273849, 0.997805354495957274562, 0.998745614468095114704, 0.999380338025023581928, 0.999760490924432047330, 0.999943996207054375764, 0.999997596379748464620, -0.999999672956734384381, -0.999992298136257588028, -0.999966730098486276883, -0.999913081144678282800, -0.999822363679787739196, -0.999686286448317731776, -0.999497112467187190535, -0.999247618943342473599, -0.998931050830810562236, -0.998541055697167906027, -0.998071634524930323302, -0.997517116063472399965, -0.996872143485260161299, -0.996131662079315037786, -0.995290903148810302261, -0.994345364356723405931, -0.993290788851684966211, -0.992123145530863117683, -0.990838611958294243677, -0.989433560520240838716, -0.987904547695124280467, -0.986248305913007552681, -0.984461737328814534596, -0.982541908851080604251, -0.980486047876721339416, -0.978291538324758539526, -0.975955916702011753129, -0.973476868052506926773, -0.970852221732792443256, -0.968079947017759947964, -0.965158148579915665979, -0.962085061904651475741, -0.958859048710200221356, -0.955478592438183697574, -0.951942293872573589498, -0.948248866934137357063, -0.944397134685866648591, -0.940386025573669721370, -0.936214569916450806625, -0.931881896650953639345, -0.927387230329536696843, -0.922729888363349241523, -0.917909278499077501636, -0.912924896514370590080, -0.907776324115058903624, -0.902463227016165675048, -0.896985353188316590376, -0.891342531251319871666, -0.885534668997285008926, -0.879561752026556262568, -0.873423842480859310192, -0.867121077859315215614, -0.860653669904299969802, -0.854021903545468625813, -0.847226135891580884381, -0.840266795261030442350, -0.833144380243172624728, -0.825859458783650001088, -0.818412667287925807395, -0.810804709738146594361, -0.803036356819268687782, -0.795108445051100526780, -0.787021875923539422170, -0.778777615032822744702, -0.770376691217076824278, -0.761820195689839149173, -0.753109281170558142523, -0.744245161011347082309, -0.735229108319491547663, -0.726062455075389632685, -0.716746591245747095767, -0.707282963891961103412, -0.697673076273711232906, -0.687918486947839325756, -0.678020808862644517838, -0.667981708447749702165, -0.657802904699713735422, -0.647486168263572388782, -0.637033320510492495071, -0.626446232611719746542, -0.615726824608992638014, -0.604877064481584353319, -0.593898967210121954393, -0.582794593837318850840, -0.571566050525742833992, -0.560215487612728441818, -0.548745098662529448608, -0.537157119515795115982, -0.525453827336442687395, -0.513637539655988578507, -0.501710613415391878251, -0.489675444004456155436, -0.477534464298829155284, -0.465290143694634735858, -0.452944987140767283784, -0.440501534168875795783, -0.427962357921062742583, -0.415330064175321663764, -0.402607290368737092671, -0.389796704618470795479, -0.376901004740559344802, -0.363922917266549655269, -0.350865196458001209011, -0.337730623318886219621, -0.324522004605921855207, -0.311242171836871800300, -0.297893980296857823437, -0.284480308042725577496, -0.271004054905512543536, -0.257468141491069790481, -0.243875508178893021593, -0.230229114119222177156, -0.216531936228472628081, -0.202786968183064697557, -0.188997219411721861059, -0.175165714086311475707, -0.161295490111305257361, -0.147389598111939940054, -0.133451100421161601344, -0.119483070065440005133, -0.105488589749541988533, -0.0914707508403553909095, -0.0774326523498572825675, -0.0633773999173222898797, -0.0493081047908686267156, -0.0352278828084410232603, -0.0211398533783310883350, -0.00704713845933674648514, 0.00704713845933674648514, 0.0211398533783310883350, 0.0352278828084410232603, 0.0493081047908686267156, 0.0633773999173222898797, 0.0774326523498572825675, 0.0914707508403553909095, 0.105488589749541988533, 0.119483070065440005133, 0.133451100421161601344, 0.147389598111939940054, 0.161295490111305257361, 0.175165714086311475707, 0.188997219411721861059, 0.202786968183064697557, 0.216531936228472628081, 0.230229114119222177156, 0.243875508178893021593, 0.257468141491069790481, 0.271004054905512543536, 0.284480308042725577496, 0.297893980296857823437, 0.311242171836871800300, 0.324522004605921855207, 0.337730623318886219621, 0.350865196458001209011, 0.363922917266549655269, 0.376901004740559344802, 0.389796704618470795479, 0.402607290368737092671, 0.415330064175321663764, 0.427962357921062742583, 0.440501534168875795783, 0.452944987140767283784, 0.465290143694634735858, 0.477534464298829155284, 0.489675444004456155436, 0.501710613415391878251, 0.513637539655988578507, 0.525453827336442687395, 0.537157119515795115982, 0.548745098662529448608, 0.560215487612728441818, 0.571566050525742833992, 0.582794593837318850840, 0.593898967210121954393, 0.604877064481584353319, 0.615726824608992638014, 0.626446232611719746542, 0.637033320510492495071, 0.647486168263572388782, 0.657802904699713735422, 0.667981708447749702165, 0.678020808862644517838, 0.687918486947839325756, 0.697673076273711232906, 0.707282963891961103412, 0.716746591245747095767, 0.726062455075389632685, 0.735229108319491547663, 0.744245161011347082309, 0.753109281170558142523, 0.761820195689839149173, 0.770376691217076824278, 0.778777615032822744702, 0.787021875923539422170, 0.795108445051100526780, 0.803036356819268687782, 0.810804709738146594361, 0.818412667287925807395, 0.825859458783650001088, 0.833144380243172624728, 0.840266795261030442350, 0.847226135891580884381, 0.854021903545468625813, 0.860653669904299969802, 0.867121077859315215614, 0.873423842480859310192, 0.879561752026556262568, 0.885534668997285008926, 0.891342531251319871666, 0.896985353188316590376, 0.902463227016165675048, 0.907776324115058903624, 0.912924896514370590080, 0.917909278499077501636, 0.922729888363349241523, 0.927387230329536696843, 0.931881896650953639345, 0.936214569916450806625, 0.940386025573669721370, 0.944397134685866648591, 0.948248866934137357063, 0.951942293872573589498, 0.955478592438183697574, 0.958859048710200221356, 0.962085061904651475741, 0.965158148579915665979, 0.968079947017759947964, 0.970852221732792443256, 0.973476868052506926773, 0.975955916702011753129, 0.978291538324758539526, 0.980486047876721339416, 0.982541908851080604251, 0.984461737328814534596, 0.986248305913007552681, 0.987904547695124280467, 0.989433560520240838716, 0.990838611958294243677, 0.992123145530863117683, 0.993290788851684966211, 0.994345364356723405931, 0.995290903148810302261, 0.996131662079315037786, 0.996872143485260161299, 0.997517116063472399965, 0.998071634524930323302, 0.998541055697167906027, 0.998931050830810562236, 0.999247618943342473599, 0.999497112467187190535, 0.999686286448317731776, 0.999822363679787739196, 0.999913081144678282800, 0.999966730098486276883, 0.999992298136257588028, 0.999999672956734384381}; } void TableGaussPatterson::loadWeights(){ weights = { // 1 point rule 2.0, // 3 point rule 0.888888888888888888889, 0.555555555555555555556, 0.555555555555555555556, // 7 point rule 0.450916538658474142345, 0.268488089868333440729, 0.268488089868333440729, 0.104656226026467265194, 0.401397414775962222905, 0.401397414775962222905, 0.104656226026467265194, // 15 point rule 0.225510499798206687386, 0.134415255243784220360, 0.134415255243784220360, 0.0516032829970797396969, 0.200628529376989021034, 0.200628529376989021034, 0.0516032829970797396969, 0.0170017196299402603390, 0.0929271953151245376859, 0.171511909136391380787, 0.219156858401587496404, 0.219156858401587496404, 0.171511909136391380787, 0.0929271953151245376859, 0.0170017196299402603390, // 31 point rule 0.112755256720768691607, 0.0672077542959907035404, 0.0672077542959907035404, 0.0258075980961766535646, 0.100314278611795578771, 0.100314278611795578771, 0.0258075980961766535646, 0.00843456573932110624631, 0.0464628932617579865414, 0.0857559200499903511542, 0.109578421055924638237, 0.109578421055924638237, 0.0857559200499903511542, 0.0464628932617579865414, 0.00843456573932110624631, 0.00254478079156187441540, 0.0164460498543878109338, 0.0359571033071293220968, 0.0569795094941233574122, 0.0768796204990035310427, 0.0936271099812644736167, 0.105669893580234809744, 0.111956873020953456880, 0.111956873020953456880, 0.105669893580234809744, 0.0936271099812644736167, 0.0768796204990035310427, 0.0569795094941233574122, 0.0359571033071293220968, 0.0164460498543878109338, 0.00254478079156187441540, // 63 point rule 0.0563776283603847173877, 0.0336038771482077305417, 0.0336038771482077305417, 0.0129038001003512656260, 0.0501571393058995374137, 0.0501571393058995374137, 0.0129038001003512656260, 0.00421763044155885483908, 0.0232314466399102694433, 0.0428779600250077344929, 0.0547892105279628650322, 0.0547892105279628650322, 0.0428779600250077344929, 0.0232314466399102694433, 0.00421763044155885483908, 0.00126515655623006801137, 0.00822300795723592966926, 0.0179785515681282703329, 0.0284897547458335486125, 0.0384398102494555320386, 0.0468135549906280124026, 0.0528349467901165198621, 0.0559784365104763194076, 0.0559784365104763194076, 0.0528349467901165198621, 0.0468135549906280124026, 0.0384398102494555320386, 0.0284897547458335486125, 0.0179785515681282703329, 0.00822300795723592966926, 0.00126515655623006801137, 0.000363221481845530659694, 0.00257904979468568827243, 0.00611550682211724633968, 0.0104982469096213218983, 0.0154067504665594978021, 0.0205942339159127111492, 0.0258696793272147469108, 0.0310735511116879648799, 0.0360644327807825726401, 0.0407155101169443189339, 0.0449145316536321974143, 0.0485643304066731987159, 0.0515832539520484587768, 0.0539054993352660639269, 0.0554814043565593639878, 0.0562776998312543012726, 0.0562776998312543012726, 0.0554814043565593639878, 0.0539054993352660639269, 0.0515832539520484587768, 0.0485643304066731987159, 0.0449145316536321974143, 0.0407155101169443189339, 0.0360644327807825726401, 0.0310735511116879648799, 0.0258696793272147469108, 0.0205942339159127111492, 0.0154067504665594978021, 0.0104982469096213218983, 0.00611550682211724633968, 0.00257904979468568827243, 0.000363221481845530659694, // 127 point rule 0.0281888141801923586938, 0.0168019385741038652709, 0.0168019385741038652709, 0.00645190005017573692280, 0.0250785696529497687068, 0.0250785696529497687068, 0.00645190005017573692280, 0.00210881524572663287933, 0.0116157233199551347270, 0.0214389800125038672465, 0.0273946052639814325161, 0.0273946052639814325161, 0.0214389800125038672465, 0.0116157233199551347270, 0.00210881524572663287933, 0.000632607319362633544219, 0.00411150397865469304717, 0.00898927578406413572328, 0.0142448773729167743063, 0.0192199051247277660193, 0.0234067774953140062013, 0.0264174733950582599310, 0.0279892182552381597038, 0.0279892182552381597038, 0.0264174733950582599310, 0.0234067774953140062013, 0.0192199051247277660193, 0.0142448773729167743063, 0.00898927578406413572328, 0.00411150397865469304717, 0.000632607319362633544219, 0.000180739564445388357820, 0.00128952408261041739210, 0.00305775341017553113613, 0.00524912345480885912513, 0.00770337523327974184817, 0.0102971169579563555237, 0.0129348396636073734547, 0.0155367755558439824399, 0.0180322163903912863201, 0.0203577550584721594669, 0.0224572658268160987071, 0.0242821652033365993580, 0.0257916269760242293884, 0.0269527496676330319634, 0.0277407021782796819939, 0.0281388499156271506363, 0.0281388499156271506363, 0.0277407021782796819939, 0.0269527496676330319634, 0.0257916269760242293884, 0.0242821652033365993580, 0.0224572658268160987071, 0.0203577550584721594669, 0.0180322163903912863201, 0.0155367755558439824399, 0.0129348396636073734547, 0.0102971169579563555237, 0.00770337523327974184817, 0.00524912345480885912513, 0.00305775341017553113613, 0.00128952408261041739210, 0.000180739564445388357820, 0.0000505360952078625176247, 0.000377746646326984660274, 0.000938369848542381500794, 0.00168114286542146990631, 0.00256876494379402037313, 0.00357289278351729964938, 0.00467105037211432174741, 0.00584344987583563950756, 0.00707248999543355546805, 0.00834283875396815770558, 0.00964117772970253669530, 0.0109557333878379016480, 0.0122758305600827700870, 0.0135915710097655467896, 0.0148936416648151820348, 0.0161732187295777199419, 0.0174219301594641737472, 0.0186318482561387901863, 0.0197954950480974994880, 0.0209058514458120238522, 0.0219563663053178249393, 0.0229409642293877487608, 0.0238540521060385400804, 0.0246905247444876769091, 0.0254457699654647658126, 0.0261156733767060976805, 0.0266966229274503599062, 0.0271855132296247918192, 0.0275797495664818730349, 0.0278772514766137016085, 0.0280764557938172466068, 0.0281763190330166021307, 0.0281763190330166021307, 0.0280764557938172466068, 0.0278772514766137016085, 0.0275797495664818730349, 0.0271855132296247918192, 0.0266966229274503599062, 0.0261156733767060976805, 0.0254457699654647658126, 0.0246905247444876769091, 0.0238540521060385400804, 0.0229409642293877487608, 0.0219563663053178249393, 0.0209058514458120238522, 0.0197954950480974994880, 0.0186318482561387901863, 0.0174219301594641737472, 0.0161732187295777199419, 0.0148936416648151820348, 0.0135915710097655467896, 0.0122758305600827700870, 0.0109557333878379016480, 0.00964117772970253669530, 0.00834283875396815770558, 0.00707248999543355546805, 0.00584344987583563950756, 0.00467105037211432174741, 0.00357289278351729964938, 0.00256876494379402037313, 0.00168114286542146990631, 0.000938369848542381500794, 0.000377746646326984660274, 0.0000505360952078625176247, // 255 point rule 0.14094407090096179347E-1, 0.84009692870519326354E-2, 0.84009692870519326354E-2, 0.32259500250878684614E-2, 0.12539284826474884353E-1, 0.12539284826474884353E-1, 0.32259500250878684614E-2, 0.10544076228633167722E-2, 0.58078616599775673635E-2, 0.10719490006251933623E-1, 0.13697302631990716258E-1, 0.13697302631990716258E-1, 0.10719490006251933623E-1, 0.58078616599775673635E-2, 0.10544076228633167722E-2, 0.31630366082226447689E-3, 0.20557519893273465236E-2, 0.44946378920320678616E-2, 0.71224386864583871532E-2, 0.96099525623638830097E-2, 0.11703388747657003101E-1, 0.13208736697529129966E-1, 0.13994609127619079852E-1, 0.13994609127619079852E-1, 0.13208736697529129966E-1, 0.11703388747657003101E-1, 0.96099525623638830097E-2, 0.71224386864583871532E-2, 0.44946378920320678616E-2, 0.20557519893273465236E-2, 0.31630366082226447689E-3, 0.90372734658751149261E-4, 0.64476204130572477933E-3, 0.15288767050877655684E-2, 0.26245617274044295626E-2, 0.38516876166398709241E-2, 0.51485584789781777618E-2, 0.64674198318036867274E-2, 0.77683877779219912200E-2, 0.90161081951956431600E-2, 0.10178877529236079733E-1, 0.11228632913408049354E-1, 0.12141082601668299679E-1, 0.12895813488012114694E-1, 0.13476374833816515982E-1, 0.13870351089139840997E-1, 0.14069424957813575318E-1, 0.14069424957813575318E-1, 0.13870351089139840997E-1, 0.13476374833816515982E-1, 0.12895813488012114694E-1, 0.12141082601668299679E-1, 0.11228632913408049354E-1, 0.10178877529236079733E-1, 0.90161081951956431600E-2, 0.77683877779219912200E-2, 0.64674198318036867274E-2, 0.51485584789781777618E-2, 0.38516876166398709241E-2, 0.26245617274044295626E-2, 0.15288767050877655684E-2, 0.64476204130572477933E-3, 0.90372734658751149261E-4, 0.25157870384280661489E-4, 0.18887326450650491366E-3, 0.46918492424785040975E-3, 0.84057143271072246365E-3, 0.12843824718970101768E-2, 0.17864463917586498247E-2, 0.23355251860571608737E-2, 0.29217249379178197538E-2, 0.35362449977167777340E-2, 0.41714193769840788528E-2, 0.48205888648512683476E-2, 0.54778666939189508240E-2, 0.61379152800413850435E-2, 0.67957855048827733948E-2, 0.74468208324075910174E-2, 0.80866093647888599710E-2, 0.87109650797320868736E-2, 0.93159241280693950932E-2, 0.98977475240487497440E-2, 0.10452925722906011926E-1, 0.10978183152658912470E-1, 0.11470482114693874380E-1, 0.11927026053019270040E-1, 0.12345262372243838455E-1, 0.12722884982732382906E-1, 0.13057836688353048840E-1, 0.13348311463725179953E-1, 0.13592756614812395910E-1, 0.13789874783240936517E-1, 0.13938625738306850804E-1, 0.14038227896908623303E-1, 0.14088159516508301065E-1, 0.14088159516508301065E-1, 0.14038227896908623303E-1, 0.13938625738306850804E-1, 0.13789874783240936517E-1, 0.13592756614812395910E-1, 0.13348311463725179953E-1, 0.13057836688353048840E-1, 0.12722884982732382906E-1, 0.12345262372243838455E-1, 0.11927026053019270040E-1, 0.11470482114693874380E-1, 0.10978183152658912470E-1, 0.10452925722906011926E-1, 0.98977475240487497440E-2, 0.93159241280693950932E-2, 0.87109650797320868736E-2, 0.80866093647888599710E-2, 0.74468208324075910174E-2, 0.67957855048827733948E-2, 0.61379152800413850435E-2, 0.54778666939189508240E-2, 0.48205888648512683476E-2, 0.41714193769840788528E-2, 0.35362449977167777340E-2, 0.29217249379178197538E-2, 0.23355251860571608737E-2, 0.17864463917586498247E-2, 0.12843824718970101768E-2, 0.84057143271072246365E-3, 0.46918492424785040975E-3, 0.18887326450650491366E-3, 0.25157870384280661489E-4, 0.69379364324108267170E-5, 0.53275293669780613125E-4, 0.13575491094922871973E-3, 0.24921240048299729402E-3, 0.38974528447328229322E-3, 0.55429531493037471492E-3, 0.74028280424450333046E-3, 0.94536151685852538246E-3, 0.11674841174299594077E-2, 0.14049079956551446427E-2, 0.16561127281544526052E-2, 0.19197129710138724125E-2, 0.21944069253638388388E-2, 0.24789582266575679307E-2, 0.27721957645934509940E-2, 0.30730184347025783234E-2, 0.33803979910869203823E-2, 0.36933779170256508183E-2, 0.40110687240750233989E-2, 0.43326409680929828545E-2, 0.46573172997568547773E-2, 0.49843645647655386012E-2, 0.53130866051870565663E-2, 0.56428181013844441585E-2, 0.59729195655081658049E-2, 0.63027734490857587172E-2, 0.66317812429018878941E-2, 0.69593614093904229394E-2, 0.72849479805538070639E-2, 0.76079896657190565832E-2, 0.79279493342948491103E-2, 0.82443037630328680306E-2, 0.85565435613076896192E-2, 0.88641732094824942641E-2, 0.91667111635607884067E-2, 0.94636899938300652943E-2, 0.97546565363174114611E-2, 0.10039172044056840798E-1, 0.10316812330947621682E-1, 0.10587167904885197931E-1, 0.10849844089337314099E-1, 0.11104461134006926537E-1, 0.11350654315980596602E-1, 0.11588074033043952568E-1, 0.11816385890830235763E-1, 0.12035270785279562630E-1, 0.12244424981611985899E-1, 0.12443560190714035263E-1, 0.12632403643542078765E-1, 0.12810698163877361967E-1, 0.12978202239537399286E-1, 0.13134690091960152836E-1, 0.13279951743930530650E-1, 0.13413793085110098513E-1, 0.13536035934956213614E-1, 0.13646518102571291428E-1, 0.13745093443001896632E-1, 0.13831631909506428676E-1, 0.13906019601325461264E-1, 0.13968158806516938516E-1, 0.14017968039456608810E-1, 0.14055382072649964277E-1, 0.14080351962553661325E-1, 0.14092845069160408355E-1, 0.14092845069160408355E-1, 0.14080351962553661325E-1, 0.14055382072649964277E-1, 0.14017968039456608810E-1, 0.13968158806516938516E-1, 0.13906019601325461264E-1, 0.13831631909506428676E-1, 0.13745093443001896632E-1, 0.13646518102571291428E-1, 0.13536035934956213614E-1, 0.13413793085110098513E-1, 0.13279951743930530650E-1, 0.13134690091960152836E-1, 0.12978202239537399286E-1, 0.12810698163877361967E-1, 0.12632403643542078765E-1, 0.12443560190714035263E-1, 0.12244424981611985899E-1, 0.12035270785279562630E-1, 0.11816385890830235763E-1, 0.11588074033043952568E-1, 0.11350654315980596602E-1, 0.11104461134006926537E-1, 0.10849844089337314099E-1, 0.10587167904885197931E-1, 0.10316812330947621682E-1, 0.10039172044056840798E-1, 0.97546565363174114611E-2, 0.94636899938300652943E-2, 0.91667111635607884067E-2, 0.88641732094824942641E-2, 0.85565435613076896192E-2, 0.82443037630328680306E-2, 0.79279493342948491103E-2, 0.76079896657190565832E-2, 0.72849479805538070639E-2, 0.69593614093904229394E-2, 0.66317812429018878941E-2, 0.63027734490857587172E-2, 0.59729195655081658049E-2, 0.56428181013844441585E-2, 0.53130866051870565663E-2, 0.49843645647655386012E-2, 0.46573172997568547773E-2, 0.43326409680929828545E-2, 0.40110687240750233989E-2, 0.36933779170256508183E-2, 0.33803979910869203823E-2, 0.30730184347025783234E-2, 0.27721957645934509940E-2, 0.24789582266575679307E-2, 0.21944069253638388388E-2, 0.19197129710138724125E-2, 0.16561127281544526052E-2, 0.14049079956551446427E-2, 0.11674841174299594077E-2, 0.94536151685852538246E-3, 0.74028280424450333046E-3, 0.55429531493037471492E-3, 0.38974528447328229322E-3, 0.24921240048299729402E-3, 0.13575491094922871973E-3, 0.53275293669780613125E-4, 0.69379364324108267170E-5, // 511 point rule 0.704720354504808967346E-2, 0.420048464352596631772E-2, 0.420048464352596631772E-2, 0.161297501254393423070E-2, 0.626964241323744217671E-2, 0.626964241323744217671E-2, 0.161297501254393423070E-2, 0.527203811431658386125E-3, 0.290393082998878368175E-2, 0.535974500312596681161E-2, 0.684865131599535812903E-2, 0.684865131599535812903E-2, 0.535974500312596681161E-2, 0.290393082998878368175E-2, 0.527203811431658386125E-3, 0.158151830411132242924E-3, 0.102787599466367326179E-2, 0.224731894601603393082E-2, 0.356121934322919357659E-2, 0.480497628118194150483E-2, 0.585169437382850155033E-2, 0.660436834876456498276E-2, 0.699730456380953992594E-2, 0.699730456380953992594E-2, 0.660436834876456498276E-2, 0.585169437382850155033E-2, 0.480497628118194150483E-2, 0.356121934322919357659E-2, 0.224731894601603393082E-2, 0.102787599466367326179E-2, 0.158151830411132242924E-3, 0.451863674126296143105E-4, 0.322381020652862389664E-3, 0.764438352543882784191E-3, 0.131228086370221478128E-2, 0.192584380831993546204E-2, 0.257427923948908888092E-2, 0.323370991590184336368E-2, 0.388419388896099560998E-2, 0.450805409759782158001E-2, 0.508943876461803986674E-2, 0.561431645670402467678E-2, 0.607054130083414983949E-2, 0.644790674400605734710E-2, 0.673818741690825799086E-2, 0.693517554456992049848E-2, 0.703471247890678765907E-2, 0.703471247890678765907E-2, 0.693517554456992049848E-2, 0.673818741690825799086E-2, 0.644790674400605734710E-2, 0.607054130083414983949E-2, 0.561431645670402467678E-2, 0.508943876461803986674E-2, 0.450805409759782158001E-2, 0.388419388896099560998E-2, 0.323370991590184336368E-2, 0.257427923948908888092E-2, 0.192584380831993546204E-2, 0.131228086370221478128E-2, 0.764438352543882784191E-3, 0.322381020652862389664E-3, 0.451863674126296143105E-4, 0.125792781889592743525E-4, 0.944366322532705527066E-4, 0.234592462123925204879E-3, 0.420285716355361231823E-3, 0.642191235948505088403E-3, 0.893223195879324912340E-3, 0.116776259302858043685E-2, 0.146086246895890987689E-2, 0.176812249885838886701E-2, 0.208570968849203942640E-2, 0.241029443242563417382E-2, 0.273893334695947541201E-2, 0.306895764002069252174E-2, 0.339789275244138669739E-2, 0.372341041620379550870E-2, 0.404330468239442998549E-2, 0.435548253986604343679E-2, 0.465796206403469754658E-2, 0.494887376202437487201E-2, 0.522646286145300596306E-2, 0.548909157632945623482E-2, 0.573524105734693719020E-2, 0.596351302650963502011E-2, 0.617263118612191922727E-2, 0.636144249136619145314E-2, 0.652891834417652442012E-2, 0.667415573186258997654E-2, 0.679637830740619795480E-2, 0.689493739162046825872E-2, 0.696931286915342540213E-2, 0.701911394845431165171E-2, 0.704407975825415053266E-2, 0.704407975825415053266E-2, 0.701911394845431165171E-2, 0.696931286915342540213E-2, 0.689493739162046825872E-2, 0.679637830740619795480E-2, 0.667415573186258997654E-2, 0.652891834417652442012E-2, 0.636144249136619145314E-2, 0.617263118612191922727E-2, 0.596351302650963502011E-2, 0.573524105734693719020E-2, 0.548909157632945623482E-2, 0.522646286145300596306E-2, 0.494887376202437487201E-2, 0.465796206403469754658E-2, 0.435548253986604343679E-2, 0.404330468239442998549E-2, 0.372341041620379550870E-2, 0.339789275244138669739E-2, 0.306895764002069252174E-2, 0.273893334695947541201E-2, 0.241029443242563417382E-2, 0.208570968849203942640E-2, 0.176812249885838886701E-2, 0.146086246895890987689E-2, 0.116776259302858043685E-2, 0.893223195879324912340E-3, 0.642191235948505088403E-3, 0.420285716355361231823E-3, 0.234592462123925204879E-3, 0.944366322532705527066E-4, 0.125792781889592743525E-4, 0.345456507169149134898E-5, 0.266376412339000901358E-4, 0.678774554733972416227E-4, 0.124606200241498368482E-3, 0.194872642236641146532E-3, 0.277147657465187357459E-3, 0.370141402122251665232E-3, 0.472680758429262691232E-3, 0.583742058714979703847E-3, 0.702453997827572321358E-3, 0.828056364077226302608E-3, 0.959856485506936206261E-3, 0.109720346268191941940E-2, 0.123947911332878396534E-2, 0.138609788229672549700E-2, 0.153650921735128916170E-2, 0.169019899554346019117E-2, 0.184668895851282540913E-2, 0.200553436203751169944E-2, 0.216632048404649142727E-2, 0.232865864987842738864E-2, 0.249218228238276930060E-2, 0.265654330259352828314E-2, 0.282140905069222207923E-2, 0.298645978275408290247E-2, 0.315138672454287935858E-2, 0.331589062145094394706E-2, 0.347968070469521146972E-2, 0.364247399027690353194E-2, 0.380399483285952829161E-2, 0.396397466714742455513E-2, 0.412215188151643401528E-2, 0.427827178065384480959E-2, 0.443208660474124713206E-2, 0.458335558178039420335E-2, 0.473184499691503264714E-2, 0.487732826815870573054E-2, 0.501958602202842039909E-2, 0.515840616547381084096E-2, 0.529358395244259896547E-2, 0.542492204466865704951E-2, 0.555223056700346326850E-2, 0.567532715799029830087E-2, 0.579403701652197628421E-2, 0.590819294541511788161E-2, 0.601763539263978131522E-2, 0.612221249080599294931E-2, 0.622178009535701763157E-2, 0.631620182177103938227E-2, 0.640534908193868098342E-2, 0.648910111976869964292E-2, 0.656734504598007641819E-2, 0.663997587196526532519E-2, 0.670689654255504925648E-2, 0.676801796747810680683E-2, 0.682325905128564571420E-2, 0.687254672150094831613E-2, 0.691581595475321433825E-2, 0.695300980066273063177E-2, 0.698407940325846925786E-2, 0.700898401972830440494E-2, 0.702769103632498213858E-2, 0.704017598127683066242E-2, 0.704642253458020417748E-2, 0.704642253458020417748E-2, 0.704017598127683066242E-2, 0.702769103632498213858E-2, 0.700898401972830440494E-2, 0.698407940325846925786E-2, 0.695300980066273063177E-2, 0.691581595475321433825E-2, 0.687254672150094831613E-2, 0.682325905128564571420E-2, 0.676801796747810680683E-2, 0.670689654255504925648E-2, 0.663997587196526532519E-2, 0.656734504598007641819E-2, 0.648910111976869964292E-2, 0.640534908193868098342E-2, 0.631620182177103938227E-2, 0.622178009535701763157E-2, 0.612221249080599294931E-2, 0.601763539263978131522E-2, 0.590819294541511788161E-2, 0.579403701652197628421E-2, 0.567532715799029830087E-2, 0.555223056700346326850E-2, 0.542492204466865704951E-2, 0.529358395244259896547E-2, 0.515840616547381084096E-2, 0.501958602202842039909E-2, 0.487732826815870573054E-2, 0.473184499691503264714E-2, 0.458335558178039420335E-2, 0.443208660474124713206E-2, 0.427827178065384480959E-2, 0.412215188151643401528E-2, 0.396397466714742455513E-2, 0.380399483285952829161E-2, 0.364247399027690353194E-2, 0.347968070469521146972E-2, 0.331589062145094394706E-2, 0.315138672454287935858E-2, 0.298645978275408290247E-2, 0.282140905069222207923E-2, 0.265654330259352828314E-2, 0.249218228238276930060E-2, 0.232865864987842738864E-2, 0.216632048404649142727E-2, 0.200553436203751169944E-2, 0.184668895851282540913E-2, 0.169019899554346019117E-2, 0.153650921735128916170E-2, 0.138609788229672549700E-2, 0.123947911332878396534E-2, 0.109720346268191941940E-2, 0.959856485506936206261E-3, 0.828056364077226302608E-3, 0.702453997827572321358E-3, 0.583742058714979703847E-3, 0.472680758429262691232E-3, 0.370141402122251665232E-3, 0.277147657465187357459E-3, 0.194872642236641146532E-3, 0.124606200241498368482E-3, 0.678774554733972416227E-4, 0.266376412339000901358E-4, 0.345456507169149134898E-5, 0.945715933950007048827E-6, 0.736624069102321668857E-5, 0.190213681905875816679E-4, 0.353751372055189588628E-4, 0.560319507856164252140E-4, 0.806899228014035293851E-4, 0.109085545645741522051E-3, 0.140970302204104791413E-3, 0.176126765545083195474E-3, 0.214368090034216937149E-3, 0.255525589595236862014E-3, 0.299439176850911730874E-3, 0.345954492129903871350E-3, 0.394924138246873704434E-3, 0.446209810101403247488E-3, 0.499683553312800484519E-3, 0.555227733977307579715E-3, 0.612734008012225209294E-3, 0.672101776960108194646E-3, 0.733236554224767912055E-3, 0.796048517297550871506E-3, 0.860451377808527848128E-3, 0.926361595613111283368E-3, 0.993697899638760857945E-3, 0.106238104885340071375E-2, 0.113233376051597664917E-2, 0.120348074001265964881E-2, 0.127574875977346947345E-2, 0.134906674928353113127E-2, 0.142336587141720519900E-2, 0.149857957106456636214E-2, 0.157464359003212166189E-2, 0.165149594771914570655E-2, 0.172907689054461607168E-2, 0.180732881501808930079E-2, 0.188619617015808475394E-2, 0.196562534503150547732E-2, 0.204556454679958293446E-2, 0.212596367401472533045E-2, 0.220677418916003329194E-2, 0.228794899365195972378E-2, 0.236944230779380495146E-2, 0.245120955750556483923E-2, 0.253320726907925325750E-2, 0.261539297272236109225E-2, 0.269772511525294586667E-2, 0.278016298199139435045E-2, 0.286266662764757868253E-2, 0.294519681581857582284E-2, 0.302771496658198544480E-2, 0.311018311158427546158E-2, 0.319256385597434736790E-2, 0.327482034651233969564E-2, 0.335691624518616761342E-2, 0.343881570768790591876E-2, 0.352048336613417922682E-2, 0.360188431545532431869E-2, 0.368298410292403911967E-2, 0.376374872034296338241E-2, 0.384414459846013158917E-2, 0.392413860322995774660E-2, 0.400369803358421688562E-2, 0.408279062042157838350E-2, 0.416138452656509745764E-2, 0.423944834747438184434E-2, 0.431695111253279479928E-2, 0.439386228676004195260E-2, 0.447015177282692726900E-2, 0.454578991327213285488E-2, 0.462074749284080687482E-2, 0.469499574088179046532E-2, 0.476850633375474925263E-2, 0.484125139721057135214E-2, 0.491320350871841897367E-2, 0.498433569972103029914E-2, 0.505462145780650125058E-2, 0.512403472879005351831E-2, 0.519254991870341614863E-2, 0.526014189569259311205E-2, 0.532678599182711857974E-2, 0.539245800482555593606E-2, 0.545713419970309863995E-2, 0.552079131034778706457E-2, 0.558340654103215637610E-2, 0.564495756786715368885E-2, 0.570542254020497332312E-2, 0.576478008199711142954E-2, 0.582300929311348057702E-2, 0.588008975062788803205E-2, 0.593600151007459827614E-2, 0.599072510668009471472E-2, 0.604424155657354634589E-2, 0.609653235797888692923E-2, 0.614757949239083790214E-2, 0.619736542573665996342E-2, 0.624587310952490748541E-2, 0.629308598198198836688E-2, 0.633898796917690165912E-2, 0.638356348613413709795E-2, 0.642679743793437438922E-2, 0.646867522080231481688E-2, 0.650918272318071200827E-2, 0.654830632678944064054E-2, 0.658603290766824937794E-2, 0.662234983720168509457E-2, 0.665724498312454708217E-2, 0.669070671050613006584E-2, 0.672272388271144108036E-2, 0.675328586233752529078E-2, 0.678238251212300746082E-2, 0.681000419582894688374E-2, 0.683614177908911221841E-2, 0.686078663022780697951E-2, 0.688393062104341470995E-2, 0.690556612755588354803E-2, 0.692568603071643155621E-2, 0.694428371707782549438E-2, 0.696135307942366551493E-2, 0.697688851735519545845E-2, 0.699088493783425207545E-2, 0.700333775568106572820E-2, 0.701424289402572916425E-2, 0.702359678471225911031E-2, 0.703139636865428709508E-2, 0.703763909614153052319E-2, 0.704232292709631209597E-2, 0.704544633127951476780E-2, 0.704700828844548013730E-2, 0.704700828844548013730E-2, 0.704544633127951476780E-2, 0.704232292709631209597E-2, 0.703763909614153052319E-2, 0.703139636865428709508E-2, 0.702359678471225911031E-2, 0.701424289402572916425E-2, 0.700333775568106572820E-2, 0.699088493783425207545E-2, 0.697688851735519545845E-2, 0.696135307942366551493E-2, 0.694428371707782549438E-2, 0.692568603071643155621E-2, 0.690556612755588354803E-2, 0.688393062104341470995E-2, 0.686078663022780697951E-2, 0.683614177908911221841E-2, 0.681000419582894688374E-2, 0.678238251212300746082E-2, 0.675328586233752529078E-2, 0.672272388271144108036E-2, 0.669070671050613006584E-2, 0.665724498312454708217E-2, 0.662234983720168509457E-2, 0.658603290766824937794E-2, 0.654830632678944064054E-2, 0.650918272318071200827E-2, 0.646867522080231481688E-2, 0.642679743793437438922E-2, 0.638356348613413709795E-2, 0.633898796917690165912E-2, 0.629308598198198836688E-2, 0.624587310952490748541E-2, 0.619736542573665996342E-2, 0.614757949239083790214E-2, 0.609653235797888692923E-2, 0.604424155657354634589E-2, 0.599072510668009471472E-2, 0.593600151007459827614E-2, 0.588008975062788803205E-2, 0.582300929311348057702E-2, 0.576478008199711142954E-2, 0.570542254020497332312E-2, 0.564495756786715368885E-2, 0.558340654103215637610E-2, 0.552079131034778706457E-2, 0.545713419970309863995E-2, 0.539245800482555593606E-2, 0.532678599182711857974E-2, 0.526014189569259311205E-2, 0.519254991870341614863E-2, 0.512403472879005351831E-2, 0.505462145780650125058E-2, 0.498433569972103029914E-2, 0.491320350871841897367E-2, 0.484125139721057135214E-2, 0.476850633375474925263E-2, 0.469499574088179046532E-2, 0.462074749284080687482E-2, 0.454578991327213285488E-2, 0.447015177282692726900E-2, 0.439386228676004195260E-2, 0.431695111253279479928E-2, 0.423944834747438184434E-2, 0.416138452656509745764E-2, 0.408279062042157838350E-2, 0.400369803358421688562E-2, 0.392413860322995774660E-2, 0.384414459846013158917E-2, 0.376374872034296338241E-2, 0.368298410292403911967E-2, 0.360188431545532431869E-2, 0.352048336613417922682E-2, 0.343881570768790591876E-2, 0.335691624518616761342E-2, 0.327482034651233969564E-2, 0.319256385597434736790E-2, 0.311018311158427546158E-2, 0.302771496658198544480E-2, 0.294519681581857582284E-2, 0.286266662764757868253E-2, 0.278016298199139435045E-2, 0.269772511525294586667E-2, 0.261539297272236109225E-2, 0.253320726907925325750E-2, 0.245120955750556483923E-2, 0.236944230779380495146E-2, 0.228794899365195972378E-2, 0.220677418916003329194E-2, 0.212596367401472533045E-2, 0.204556454679958293446E-2, 0.196562534503150547732E-2, 0.188619617015808475394E-2, 0.180732881501808930079E-2, 0.172907689054461607168E-2, 0.165149594771914570655E-2, 0.157464359003212166189E-2, 0.149857957106456636214E-2, 0.142336587141720519900E-2, 0.134906674928353113127E-2, 0.127574875977346947345E-2, 0.120348074001265964881E-2, 0.113233376051597664917E-2, 0.106238104885340071375E-2, 0.993697899638760857945E-3, 0.926361595613111283368E-3, 0.860451377808527848128E-3, 0.796048517297550871506E-3, 0.733236554224767912055E-3, 0.672101776960108194646E-3, 0.612734008012225209294E-3, 0.555227733977307579715E-3, 0.499683553312800484519E-3, 0.446209810101403247488E-3, 0.394924138246873704434E-3, 0.345954492129903871350E-3, 0.299439176850911730874E-3, 0.255525589595236862014E-3, 0.214368090034216937149E-3, 0.176126765545083195474E-3, 0.140970302204104791413E-3, 0.109085545645741522051E-3, 0.806899228014035293851E-4, 0.560319507856164252140E-4, 0.353751372055189588628E-4, 0.190213681905875816679E-4, 0.736624069102321668857E-5, 0.945715933950007048827E-6}; } } #endif TASMANIAN-8.1/SparseGrids/tsgHardCodedTabulatedRules.hpp000066400000000000000000000107001470551176200230360ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_HARDCODED_RULES_HPP #define __TASMANIAN_SPARSE_HARDCODED_RULES_HPP /*! * \internal * \file tsgHardCodedTabulatedRules.hpp * \brief Hard-coded nodes and weights. * \author Miroslav Stoyanov * \ingroup TasmanianSets * * Some rules are hard to compute on the fly, thus points and weights are hard-coded. * \endinternal */ #include "tsgCoreOneDimensional.hpp" namespace TasGrid{ /*! * \internal * \ingroup TasmanianCoreOneDimensional * \brief Rule with hard-corded tabulated points and weights. * * The Gauss-Patterson rule combines nested points with the optimality of the Gauss quadratures. * While not as powerful as Gauss-Legendre in one and tow dimensions, the rule wins in * polynomial space of exactness with respect to integration for 3 or more dimensions. * However, the points and weights are very hard to compute and most algorithms are very * ill-conditioned. Thus, it is beneficial to have the points for the first 9 levels hard-coded. * * Note that Gauss-Legendre rule combined with a full tensor grid gives highest exactness per * number of points with respect to integration in one and two dimensions. * \endinternal */ class TableGaussPatterson{ public: //! \brief Constructor, loads the nodes into the internal data structures. TableGaussPatterson(); //! \brief Destrutor, cleans all memory. ~TableGaussPatterson() = default; //! \brief Return the number of hard-coded levels. static int getNumLevels(){ return 9; } //! \brief Returns the nodes for the \b level, note that the nodes are nested. std::vector getNodes(int level) const; //! \brief Return the quadrature weight for \b level and given \b point. double getWeight(int level, int point) const; protected: //! \brief Load the nodes into the local data-strutures. void loadNodes(); //! \brief Load the weights into the local data-structures. void loadWeights(); private: std::vector nodes; // contains the x-coordinate of each sample point std::vector weights; // contains the weight associated with each level std::vector weights_offsets; }; } #endif TASMANIAN-8.1/SparseGrids/tsgHierarchyManipulator.cpp000066400000000000000000000413571470551176200225210ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_HIERARCHY_MANIPULATOR_CPP #define __TSG_HIERARCHY_MANIPULATOR_CPP #include "tsgHierarchyManipulator.hpp" namespace TasGrid{ namespace HierarchyManipulations{ template Data2D computeDAGup(MultiIndexSet const &mset){ size_t num_dimensions = mset.getNumDimensions(); int num_points = mset.getNumIndexes(); if (RuleLocal::getMaxNumParents() > 1){ // allow for multiple parents and level 0 may have more than one node int max_parents = RuleLocal::getMaxNumParents() * (int) num_dimensions; Data2D parents(max_parents, num_points, -1); int level0_offset = RuleLocal::getNumPoints(0); #pragma omp parallel for schedule(static) for(int i=0; i dad(num_dimensions); std::copy_n(p, num_dimensions, dad.data()); int *pp = parents.getStrip(i); for(size_t j=0; j= level0_offset){ int current = p[j]; dad[j] = RuleLocal::getParent(current); pp[2*j] = mset.getSlot(dad); while ((dad[j] >= level0_offset) && (pp[2*j] == -1)){ current = dad[j]; dad[j] = RuleLocal::getParent(current); pp[2*j] = mset.getSlot(dad); } dad[j] = RuleLocal::getStepParent(current); if (dad[j] != -1){ pp[2*j + 1] = mset.getSlot(dad); } dad[j] = p[j]; } } } return parents; }else{ // this assumes that level zero has only one node Data2D parents((int) num_dimensions, num_points); #pragma omp parallel for schedule(static) for(int i=0; i dad(num_dimensions); std::copy_n(p, num_dimensions, dad.data()); int *pp = parents.getStrip(i); for(size_t j=0; j(dad[j]); pp[j] = mset.getSlot(dad.data()); while((dad[j] != 0) && (pp[j] == -1)){ dad[j] = RuleLocal::getParent(dad[j]); pp[j] = mset.getSlot(dad); } dad[j] = p[j]; } } } return parents; } } template Data2D computeDAGup(MultiIndexSet const &mset); template Data2D computeDAGup(MultiIndexSet const &mset); template Data2D computeDAGup(MultiIndexSet const &mset); template Data2D computeDAGup(MultiIndexSet const &mset); template Data2D computeDAGup(MultiIndexSet const &mset); Data2D computeDAGup(MultiIndexSet const &mset, RuleLocal::erule effrule) { switch(effrule) { case RuleLocal::erule::pwc: return computeDAGup(mset); case RuleLocal::erule::localp: return computeDAGup(mset); case RuleLocal::erule::semilocalp: return computeDAGup(mset); case RuleLocal::erule::localp0: return computeDAGup(mset); default: // case RuleLocal::erule::localpb: return computeDAGup(mset); }; } template Data2D computeDAGup(MultiIndexSet const &mset, bool &is_complete){ size_t num_dimensions = mset.getNumDimensions(); int num_points = mset.getNumIndexes(); if (RuleLocal::getMaxNumParents() > 1){ // allow for multiple parents and level 0 may have more than one node int max_parents = RuleLocal::getMaxNumParents() * (int) num_dimensions; Data2D parents(max_parents, num_points, -1); int level0_offset = RuleLocal::getNumPoints(0); int any_fail = 0; // count if there are failures #pragma omp parallel { int fail = 0; // local thread count fails #pragma omp for schedule(static) for(int i=0; i dad(num_dimensions); std::copy_n(p, num_dimensions, dad.data()); int *pp = parents.getStrip(i); for(size_t j=0; j= level0_offset){ int current = p[j]; dad[j] = RuleLocal::getParent(current); pp[2*j] = mset.getSlot(dad); if (pp[2*j] == -1) fail = 1; while ((dad[j] >= level0_offset) && (pp[2*j] == -1)){ current = dad[j]; dad[j] = RuleLocal::getParent(current); pp[2*j] = mset.getSlot(dad); } dad[j] = RuleLocal::getStepParent(current); if (dad[j] != -1){ pp[2*j + 1] = mset.getSlot(dad); if (pp[2*j + 1] == -1) fail = 1; } dad[j] = p[j]; } } } #pragma omp atomic any_fail += fail; } is_complete = (any_fail == 0); return parents; }else{ // this assumes that level zero has only one node Data2D parents((int) num_dimensions, num_points); int any_fail = 0; // count if there are failures #pragma omp parallel { int fail = 0; // local thread count fails #pragma omp for schedule(static) for(int i=0; i dad(num_dimensions); std::copy_n(p, num_dimensions, dad.data()); int *pp = parents.getStrip(i); for(size_t j=0; j(dad[j]); pp[j] = mset.getSlot(dad.data()); if (pp[j] == -1) fail = 1; while((dad[j] != 0) && (pp[j] == -1)){ dad[j] = RuleLocal::getParent(dad[j]); pp[j] = mset.getSlot(dad); } dad[j] = p[j]; } } } #pragma omp atomic any_fail += fail; } is_complete = (any_fail == 0); return parents; } } template Data2D computeDAGup(MultiIndexSet const &mset, bool &is_complete); template Data2D computeDAGup(MultiIndexSet const &mset, bool &is_complete); template Data2D computeDAGup(MultiIndexSet const &mset, bool &is_complete); template Data2D computeDAGup(MultiIndexSet const &mset, bool &is_complete); template Data2D computeDAGup(MultiIndexSet const &mset, bool &is_complete); template Data2D computeDAGDown(MultiIndexSet const &mset){ size_t num_dimensions = mset.getNumDimensions(); int max_1d_kids = RuleLocal::getMaxNumKids(); int num_points = mset.getNumIndexes(); Data2D kids(Utils::size_mult(max_1d_kids, num_dimensions), num_points); #pragma omp parallel for for(int i=0; i kid(num_dimensions); std::copy_n(mset.getIndex(i), num_dimensions, kid.data()); auto family = kids.getIStrip(i); for(size_t j=0; j(current, k); *family++ = (kid[j] == -1) ? -1 : mset.getSlot(kid); } kid[j] = current; } } return kids; } template Data2D computeDAGDown(MultiIndexSet const &mset); template Data2D computeDAGDown(MultiIndexSet const &mset); template Data2D computeDAGDown(MultiIndexSet const &mset); template Data2D computeDAGDown(MultiIndexSet const &mset); template Data2D computeDAGDown(MultiIndexSet const &mset); template std::vector computeLevels(MultiIndexSet const &mset){ size_t num_dimensions = mset.getNumDimensions(); int num_points = mset.getNumIndexes(); std::vector level((size_t) num_points); #pragma omp parallel for schedule(static) for(int i=0; i(p[0]); for(size_t j=1; j(p[j]); } level[i] = current_level; } return level; } template std::vector computeLevels(MultiIndexSet const &mset); template std::vector computeLevels(MultiIndexSet const &mset); template std::vector computeLevels(MultiIndexSet const &mset); template std::vector computeLevels(MultiIndexSet const &mset); template std::vector computeLevels(MultiIndexSet const &mset); std::vector computeLevels(MultiIndexSet const &mset, RuleLocal::erule effrule) { switch(effrule) { case RuleLocal::erule::pwc: return computeLevels(mset); case RuleLocal::erule::localp: return computeLevels(mset); case RuleLocal::erule::semilocalp: return computeLevels(mset); case RuleLocal::erule::localp0: return computeLevels(mset); default: // case RuleLocal::erule::localpb: return computeLevels(mset); }; } template void completeToLower(MultiIndexSet const &mset, MultiIndexSet &refined){ size_t num_dimensions = mset.getNumDimensions(); size_t num_added = 1; // set to 1 to start the loop while(num_added > 0){ Data2D addons(num_dimensions, 0); int num_points = refined.getNumIndexes(); for(int i=0; i parent(refined.getIndex(i), refined.getIndex(i) + num_dimensions); for(auto &p : parent){ int r = p; p = RuleLocal::getParent(r); if ((p != -1) && refined.missing(parent) && mset.missing(parent)) addons.appendStrip(parent); p = RuleLocal::getStepParent(r); if ((p != -1) && refined.missing(parent) && mset.missing(parent)) addons.appendStrip(parent); p = r; } } num_added = addons.getNumStrips(); if (num_added > 0) refined += addons; } } template void completeToLower(MultiIndexSet const &mset, MultiIndexSet &refined); template void completeToLower(MultiIndexSet const &mset, MultiIndexSet &refined); template void completeToLower(MultiIndexSet const &mset, MultiIndexSet &refined); template void completeToLower(MultiIndexSet const &mset, MultiIndexSet &refined); template void completeToLower(MultiIndexSet const &mset, MultiIndexSet &refined); SplitDirections::SplitDirections(const MultiIndexSet &points){ // split the points into "jobs", where each job represents a batch of // points that lay on a line in some direction // int job_directions[i] gives the direction of the i-th job // vector job_pnts[i] gives a list of the points (using indexes within the set) int num_points = points.getNumIndexes(); size_t num_dimensions = points.getNumDimensions(); auto doesBelongSameLine = [&](const int a[], const int b[], size_t direction)-> bool{ for(size_t i=0; i map(num_points); std::iota(map.begin(), map.end(), 0); std::sort(map.begin(), map.end(), [&](int a, int b)->bool{ const int * idxa = points.getIndex(a); const int * idxb = points.getIndex(b); // lexigographical order ignoring dimension d for(size_t j=0; j idxb[j]) return false; } return false; }); auto imap = map.begin(); while(imap != map.end()){ // new job, get reference index const int *p = points.getIndex(*imap); job_directions.push_back((int) d); job_pnts.emplace_back(std::vector(1, *imap++)); // while the points are in the same direction as the reference, add to the same job while((imap != map.end()) && doesBelongSameLine(p, points.getIndex(*imap), d)) job_pnts.back().push_back(*imap++); } } } } // HierarchyManipulations } // TasGrid #endif TASMANIAN-8.1/SparseGrids/tsgHierarchyManipulator.hpp000066400000000000000000000336751470551176200225320ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_HIERARCHY_MANIPULATOR_HPP #define __TSG_HIERARCHY_MANIPULATOR_HPP #include "tsgRuleLocalPolynomial.hpp" #include "tsgIndexManipulator.hpp" /*! * \internal * \file tsgHierarchyManipulator.hpp * \brief Algorithms for manipulating multi-indexes defined by hierarchy rules. * \author Miroslav Stoyanov * \ingroup TasmanianHierarchyManipulations * * A series of templates, lambda, and regular functions that allow the manipulation of * multi-indexes and sets of multi-indexes defined by hierarchy rules. * \endinternal */ /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianHierarchyManipulations Hierarchical multi-Index manipulation algorithms * * \par One Dimensional Hierarchy * The construction of Global, Sequence and Fourier grids the multi-index hierarchy is associated * with tensors and has very simple structure, in one dimension there is only one parent and * one child indicated by the previous and next index. * The Local-Polynomial and Wavelet girds use more complex hierarchies that have multiple * children and (in some cases) parents. * Many of the associated manipulation algorithms require a \b rule object that * describes the hierarchy, and additional algorithms are needed to handle the more complex * parent-child relations. * * \endinternal */ namespace TasGrid{ /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Collection of algorithm to manipulate multi-indexes. */ namespace HierarchyManipulations{ /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Cache the indexes slot numbers of the parents of the multi-indexes in \b mset. * * Each node defined by a multi-index in \b mset can have one or more parents in each direction, * where the parent-offspring relation is defined by the \b rule. For each index in \b mset, the * Data2D structure \b parents will hold a strip with the location of each parent in \b mset * (or -1 if the parent is missing from \b mset). * \endinternal */ template Data2D computeDAGup(MultiIndexSet const &mset); /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Cache the indexes slot numbers of the parents of the multi-indexes in \b mset. * * The effective rule is passed in at runtime and a switch statement finds the correct template. * \endinternal */ Data2D computeDAGup(MultiIndexSet const &mset, RuleLocal::erule effrule); /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Variant that also check if all points have all parents * * This is merged together so it will do only one pass over the data. * * On exit, \b is_complete will indicate whether there are points with missing parents. * \endinternal */ template Data2D computeDAGup(MultiIndexSet const &mset, bool &is_complete); /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Cache the indexes slot numbers of the children of the multi-indexes in \b mset. * * Each node defined by a multi-index in \b mset can have one or more children in each direction, * where the parent-offspring relation is defined by the \b rule. For each index in \b mset, the * returned Data2D structure will hold a strip with the location of each child in \b mset * (or -1 if the kid is missing from \b mset). * \endinternal */ template Data2D computeDAGDown(MultiIndexSet const &mset); /*! * \internal * \brief Returns a vector that is the sum of the one dimensional levels of each multi-index in the set. * \ingroup TasmanianHierarchyManipulations * \endinternal */ template std::vector computeLevels(MultiIndexSet const &mset); /*! * \internal * \brief Overload that turns switch statement into template instantiations * \ingroup TasmanianHierarchyManipulations * \endinternal */ std::vector computeLevels(MultiIndexSet const &mset, RuleLocal::erule effrule); /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Complete \b refined so that the union of \b refined and \b mset is lower w.r.t. the \b rule. * \endinternal */ template void completeToLower(MultiIndexSet const &mset, MultiIndexSet &refined); /*! * \internal * \brief Will call \b apply() with the slot index in \b mset of each parent/child of \b point. * \ingroup TasmanianHierarchyManipulations * \endinternal */ template void touchAllImmediateRelatives(std::vector &point, MultiIndexSet const &mset, callable_method apply){ int max_kids = RuleLocal::getMaxNumKids(); for(auto &v : point){ int save = v; // replace one by one each index of p with either parent or kid // check the parents v = RuleLocal::getParent(save); if (v > -1){ int parent_index = mset.getSlot(point); if (parent_index > -1) apply(parent_index); } v = RuleLocal::getStepParent(save); if (v > -1){ int parent_index = mset.getSlot(point); if (parent_index > -1) apply(parent_index); } for(int k=0; k(save, k); if (v > -1){ int kid_index = mset.getSlot(point); if (kid_index > -1) apply(kid_index); } } v = save; // restore the original index for the next iteration } } /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Return the tensor set of all points that sit on level zero (i.e., have no parents). * * \endinternal */ template MultiIndexSet getLevelZeroPoints(size_t num_dimensions){ int num_parents = 0; while(RuleLocal::getParent(num_parents) == -1) num_parents++; return MultiIndexManipulations::generateFullTensorSet(std::vector(num_dimensions, num_parents)); } /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Return the largest subset of \b candidates such that adding it to \b current will result in a connected graph. * * \endinternal */ template MultiIndexSet getLargestConnected(MultiIndexSet const ¤t, MultiIndexSet const &candidates){ if (candidates.empty()) return MultiIndexSet(); auto num_dimensions = candidates.getNumDimensions(); // always consider the points without parents MultiIndexSet level_zero = getLevelZeroPoints(num_dimensions); MultiIndexSet result; // keep track of the cumulative result MultiIndexSet total = current; // forms a working copy of the entire merged graph // do not consider the points already included in total, complexity is level_zero.getNumIndexes() if (!total.empty()) level_zero = level_zero - total; if (level_zero.getNumIndexes() > 0){ // level zero nodes are missing from current Data2D roots(num_dimensions, 0); for(int i=0; i p(level_zero.getIndex(i), level_zero.getIndex(i) + num_dimensions); if (!candidates.missing(p)) roots.appendStrip(p); } result = MultiIndexSet(roots); total += result; } if (total.empty()) return MultiIndexSet(); // current was empty and no roots could be added int max_kids = RuleLocal::getMaxNumKids(); int max_relatives = RuleLocal::getMaxNumParents() + max_kids; Data2D update; do{ update = Data2D(num_dimensions, 0); for(int i=0; i relative(total.getIndex(i), total.getIndex(i) + num_dimensions); for(auto &r : relative){ int k = r; // save the value for(int j=0; j(k, j) : ((j - max_kids == 0) ? RuleLocal::getParent(k) : RuleLocal::getStepParent(k)); if ((r != -1) && !candidates.missing(relative) && total.missing(relative)) update.appendStrip(relative); } r = k; } } if (update.getNumStrips() > 0){ MultiIndexSet update_set(update); result += update_set; total += update_set; } }while(update.getNumStrips() > 0); return result; } /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Split the range between \b ibegin and \b iend into strips of \b stride and orders those by levels according to the level index in \b ilevels. * * \endinternal */ template std::vector> splitByLevels(size_t stride, typename std::vector::const_iterator ibegin, typename std::vector::const_iterator iend, std::vector::const_iterator ilevels){ size_t top_level = (size_t) *std::max_element(ilevels, ilevels + std::distance(ibegin, iend) / stride); std::vector> split(top_level + 1, Data2D(stride, 0)); for( struct { std::vector::const_iterator il; typename std::vector::const_iterator idata;} v = {ilevels, ibegin}; v.idata != iend; v.il++, std::advance(v.idata, stride)) split[*v.il].appendStrip(v.idata); return split; } /*! * \ingroup TasmanianHierarchyManipulations * \brief Overload that operates on an entire multi-index set. */ inline std::vector> splitByLevels(MultiIndexSet const &mset, std::vector const &levels){ return splitByLevels(mset.getNumDimensions(), mset.begin(), mset.end(), levels.begin()); } /*! * \ingroup TasmanianHierarchyManipulations * \brief Overload that operates on an entire Data2D structure set. */ template inline std::vector> splitByLevels(Data2D const &data, std::vector const &levels){ return splitByLevels(data.getStride(), data.begin(), data.end(), levels.begin()); } /*! * \ingroup TasmanianHierarchyManipulations * \brief Overload that operates on an entire StorageSet structure set. */ inline std::vector> splitByLevels(StorageSet const &stortage, std::vector const &levels){ return splitByLevels(stortage.getNumOutputs(), stortage.begin(), stortage.end(), levels.begin()); } /*! * \internal * \ingroup TasmanianHierarchyManipulations * \brief Reorganize the \b points into sets of nodes that align in one-dimension, used for directional localp refinement. * * \endinternal */ class SplitDirections{ public: //! \brief Constructor, deinfe the set to split into directions. SplitDirections(const MultiIndexSet &points); //! \brief Destroy all data. ~SplitDirections(){} //! \brief Returns the number of one dimensional jobs. int getNumJobs() const{ return (int) job_pnts.size(); } //! \brief Return the direction for the \b job. int getJobDirection(int job) const{ return job_directions[job]; } //! \brief Return the number of points associated with the \b job. int getJobNumPoints(int job) const{ return (int) job_pnts[job].size(); } //! \brief Return the indexes of the points associated with the job. const int* getJobPoints(int job) const{ return job_pnts[job].data(); } //! \brief Return the max number of points for any job. int getMaxNumPoints() const { return (job_pnts.size() > 0) ? (int) std::max_element(job_pnts.begin(), job_pnts.end(), [&](std::vector const &a, std::vector const& b)->bool{ return (a.size() < b.size()); })->size() : 0; } private: std::vector job_directions; std::vector> job_pnts; }; } } #endif TASMANIAN-8.1/SparseGrids/tsgHipKernels.hip.cpp000066400000000000000000000537151470551176200212130ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_HIP_KERNELS_HIP #define __TASMANIAN_SPARSE_GRID_HIP_KERNELS_HIP #include "tsgAcceleratedDataStructures.hpp" #include "tsgCudaBasisEvaluations.hpp" #include "tsgCudaLinearAlgebra.hpp" // several kernels assume a linear distribution of the threads and can be executed with "practically unlimited" number of threads // thus we can set this to the HIP max number of threads, based on the current cuda version constexpr int _MAX_HIP_THREADS = 1024; // max number of blocks per grid direction constexpr int _MAX_HIP_BLOCKS = 65535; /* * Create a 1-D HIP thread grid using the total_threads and number of threads per block. * Basically, computes the number of blocks but no more than _MAX_CUDA_BLOCKS. */ struct ThreadGrid1d{ // Compute the threads and blocks. ThreadGrid1d(long long total_threads, long long num_per_block) : threads(static_cast(num_per_block)), blocks(static_cast(std::min(total_threads / threads + ((total_threads % threads == 0) ? 0 : 1), static_cast(_MAX_HIP_BLOCKS)))) {} // number of threads int const threads; // number of blocks int const blocks; }; namespace TasGrid{ template void TasGpu::dtrans2can(AccelerationContext const*, bool use01, int dims, int num_x, int pad_size, double const *gpu_trans_a, double const *gpu_trans_b, T const *gpu_x_transformed, T *gpu_x_canonical){ ThreadGrid1d task(num_x * dims, _MAX_HIP_THREADS); hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_transformed_to_canonical), task.blocks, task.threads, (2*pad_size) * sizeof(double), 0, dims, num_x, pad_size, gpu_trans_a, gpu_trans_b, gpu_x_transformed, gpu_x_canonical); if (use01) hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_m11_to_01), task.blocks, task.threads, 0, 0, dims * num_x, gpu_x_canonical); } template void TasGpu::dtrans2can(AccelerationContext const*, bool, int, int, int, double const*, double const*, double const*, double*); template void TasGpu::dtrans2can(AccelerationContext const*, bool, int, int, int, double const*, double const*, float const*, float*); // local polynomial basis functions, DENSE algorithm template void TasGpu::devalpwpoly(AccelerationContext const*, int order, TypeOneDRule rule, int dims, int num_x, int num_points, const T *gpu_x, const T *gpu_nodes, const T *gpu_support, T *gpu_y){ // each block thread runs 1024 threads and processes 32 points (or basis functions) int num_blocks = (num_points / 32) + ((num_points % 32 == 0) ? 0 : 1); // order == 1 is considered "default" so that the compiler doesn't complain about missing default statement // semilocalp cannot have order less than 2, only rule_localp can have order 0 (this gets overwrittein in makeLocalPolynomialGrid()) if (rule == rule_localp){ switch(order){ case 0: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly), num_blocks, 1024, 0, 0, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; case 2: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly), num_blocks, 1024, 0, 0, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; default: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly), num_blocks, 1024, 0, 0, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } }else if (rule == rule_localp0){ switch(order){ case 2: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly), num_blocks, 1024, 0, 0, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; default: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly), num_blocks, 1024, 0, 0, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } }else if (rule == rule_localpb){ switch(order){ case 2: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly), num_blocks, 1024, 0, 0, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); break; default: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly), num_blocks, 1024, 0, 0, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } }else if (rule == rule_semilocalp){ hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly), num_blocks, 1024, 0, 0, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); }else{ // rule == wavelet hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly), num_blocks, 1024, 0, 0, dims, num_x, num_points, gpu_x, gpu_nodes, gpu_support, gpu_y); } } template void TasGpu::devalpwpoly(AccelerationContext const*, int, TypeOneDRule, int, int, int, const double*, const double*, const double*, double*); template void TasGpu::devalpwpoly(AccelerationContext const*, int, TypeOneDRule, int, int, int, const float*, const float*, const float*, float*); // there is a switch statement that realizes templates for each combination of rule/order // make one function that covers that switch, the rest is passed from devalpwpoly_sparse template inline void devalpwpoly_sparse_realize_rule_order(int order, TypeOneDRule rule, int dims, int num_x, const T *x, const T *nodes, const T *support, const int *hpntr, const int *hindx, int num_roots, const int *roots, int *spntr, int *sindx, T *svals){ int num_blocks = num_x / THREADS + ((num_x % THREADS == 0) ? 0 : 1); if (num_blocks >= _MAX_HIP_BLOCKS) num_blocks = _MAX_HIP_BLOCKS; if (rule == rule_localp){ switch(order){ case 0: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly_sparse), num_blocks, THREADS, 0, 0, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; case 2: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly_sparse), num_blocks, THREADS, 0, 0, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; default: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly_sparse), num_blocks, THREADS, 0, 0, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } }else if (rule == rule_localp0){ switch(order){ case 2: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly_sparse), num_blocks, THREADS, 0, 0, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; default: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly_sparse), num_blocks, THREADS, 0, 0, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } }else if (rule == rule_localpb){ switch(order){ case 2: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly_sparse), num_blocks, THREADS, 0, 0, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); break; default: hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly_sparse), num_blocks, THREADS, 0, 0, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } }else{ // rule == rule_semilocalp hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_devalpwpoly_sparse), num_blocks, THREADS, 0, 0, dims, num_x, x, nodes, support, hpntr, hindx, num_roots, roots, spntr, sindx, svals); } } // local polynomial basis functions, SPARSE algorithm (2 passes, one pass to compue the non-zeros and one pass to evaluate) template void TasGpu::devalpwpoly_sparse(AccelerationContext const*, int order, TypeOneDRule rule, int dims, int num_x, const T *gpu_x, const GpuVector &gpu_nodes, const GpuVector &gpu_support, const GpuVector &gpu_hpntr, const GpuVector &gpu_hindx, const GpuVector &gpu_hroots, GpuVector &gpu_spntr, GpuVector &gpu_sindx, GpuVector &gpu_svals){ gpu_spntr.resize(nullptr, num_x + 1); // call with fill == false to count the non-zeros per row of the matrix devalpwpoly_sparse_realize_rule_order (order, rule, dims, num_x, gpu_x, gpu_nodes.data(), gpu_support.data(), gpu_hpntr.data(), gpu_hindx.data(), (int) gpu_hroots.size(), gpu_hroots.data(), gpu_spntr.data(), 0, 0); std::vector cpu_spntr; gpu_spntr.unload(nullptr, cpu_spntr); cpu_spntr[0] = 0; int nz = 0; for(auto &i : cpu_spntr){ i += nz; nz = i; } gpu_spntr.load(nullptr, cpu_spntr); gpu_sindx.resize(nullptr, nz); gpu_svals.resize(nullptr, nz); // call with fill == true to load the non-zeros devalpwpoly_sparse_realize_rule_order (order, rule, dims, num_x, gpu_x, gpu_nodes.data(), gpu_support.data(), gpu_hpntr.data(), gpu_hindx.data(), (int) gpu_hroots.size(), gpu_hroots.data(), gpu_spntr.data(), gpu_sindx.data(), gpu_svals.data()); } template void TasGpu::devalpwpoly_sparse(AccelerationContext const*, int, TypeOneDRule, int, int, const double*, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, GpuVector&, GpuVector&, GpuVector&); template void TasGpu::devalpwpoly_sparse(AccelerationContext const*, int, TypeOneDRule, int, int, const float*, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, const GpuVector&, GpuVector&, GpuVector&, GpuVector&); // Sequence Grid basis evaluations template void TasGpu::devalseq(AccelerationContext const*, int dims, int num_x, const std::vector &max_levels, const T *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, T *gpu_result){ std::vector offsets(dims); offsets[0] = 0; for(int d=1; d gpu_offsets(nullptr, offsets); GpuVector cache1D(nullptr, num_total); ThreadGrid1d task(num_x, _MAX_HIP_THREADS); hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dseq_build_cache), task.blocks, task.threads, 0, 0, dims, num_x, gpu_x, nodes.data(), coeffs.data(), maxl+1, gpu_offsets.data(), num_nodes.data(), cache1D.data()); ThreadGrid1d task_compute(num_x, 32); hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dseq_eval_sharedpoints), task_compute.blocks, 1024, 0, 0, dims, num_x, (int) points.size() / dims, points.data(), gpu_offsets.data(), cache1D.data(), gpu_result); } template void TasGpu::devalseq(AccelerationContext const*, int dims, int num_x, const std::vector &max_levels, const double *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, double *gpu_result); template void TasGpu::devalseq(AccelerationContext const*, int dims, int num_x, const std::vector &max_levels, const float *gpu_x, const GpuVector &num_nodes, const GpuVector &points, const GpuVector &nodes, const GpuVector &coeffs, float *gpu_result); // Fourier Grid basis evaluations template void TasGpu::devalfor(AccelerationContext const*, int dims, int num_x, const std::vector &max_levels, const T *gpu_x, const GpuVector &num_nodes, const GpuVector &points, T *gpu_wreal, typename GpuVector::value_type *gpu_wimag){ std::vector max_nodes(dims); for(int j=0; j offsets(dims); offsets[0] = 0; for(int d=1; d gpu_offsets(nullptr, offsets); GpuVector cache1D(nullptr, num_total); ThreadGrid1d task(num_x, _MAX_HIP_THREADS); hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dfor_build_cache), task.blocks, task.threads, 0, 0, dims, num_x, gpu_x, gpu_offsets.data(), num_nodes.data(), cache1D.data()); ThreadGrid1d task_compute(num_x, 32); if (gpu_wimag == nullptr){ hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dfor_eval_sharedpoints), task_compute.blocks, 1024, 0, 0, dims, num_x, (int) points.size() / dims, points.data(), gpu_offsets.data(), cache1D.data(), gpu_wreal, nullptr); }else{ hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dfor_eval_sharedpoints), task_compute.blocks, 1024, 0, 0, dims, num_x, (int) points.size() / dims, points.data(), gpu_offsets.data(), cache1D.data(), gpu_wreal, gpu_wimag); } } template void TasGpu::devalfor(AccelerationContext const*, int, int, const std::vector&, const double*, const GpuVector&, const GpuVector&, double*, double*); template void TasGpu::devalfor(AccelerationContext const*, int, int, const std::vector&, const float*, const GpuVector&, const GpuVector&, float*, float*); template void TasGpu::devalglo(AccelerationContext const*, bool is_nested, bool is_clenshawcurtis0, int dims, int num_x, int num_p, int num_basis, T const *gpu_x, GpuVector const &nodes, GpuVector const &coeff, GpuVector const &tensor_weights, GpuVector const &nodes_per_level, GpuVector const &offset_per_level, GpuVector const &map_dimension, GpuVector const &map_level, GpuVector const &active_tensors, GpuVector const &active_num_points, GpuVector const &dim_offsets, GpuVector const &map_tensor, GpuVector const &map_index, GpuVector const &map_reference, T *gpu_result){ GpuVector cache(nullptr, num_x, num_basis); int num_blocks = (int) map_dimension.size(); if (num_blocks >= _MAX_HIP_BLOCKS) num_blocks = _MAX_HIP_BLOCKS; if (is_nested){ if (is_clenshawcurtis0){ hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dglo_build_cache), num_blocks, _MAX_HIP_THREADS, 0, 0, dims, num_x, (int) map_dimension.size(), gpu_x, nodes.data(), coeff.data(), nodes_per_level.data(), offset_per_level.data(), dim_offsets.data(), map_dimension.data(), map_level.data(), cache.data()); }else{ hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dglo_build_cache), num_blocks, _MAX_HIP_THREADS, 0, 0, dims, num_x, (int) map_dimension.size(), gpu_x, nodes.data(), coeff.data(), nodes_per_level.data(), offset_per_level.data(), dim_offsets.data(), map_dimension.data(), map_level.data(), cache.data()); } }else{ hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dglo_build_cache), num_blocks, _MAX_HIP_THREADS, 0, 0, dims, num_x, (int) map_dimension.size(), gpu_x, nodes.data(), coeff.data(), nodes_per_level.data(), offset_per_level.data(), dim_offsets.data(), map_dimension.data(), map_level.data(), cache.data()); } int mat_size = num_x * num_p; num_blocks = num_x / _MAX_HIP_THREADS + ((mat_size % _MAX_HIP_THREADS == 0) ? 0 : 1); if (num_blocks >= _MAX_HIP_THREADS) num_blocks = _MAX_HIP_THREADS; hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dglo_eval_zero), num_blocks, _MAX_HIP_THREADS, 0, 0, mat_size, gpu_result); num_blocks = (int) map_tensor.size(); if (num_blocks >= _MAX_HIP_BLOCKS) num_blocks = _MAX_HIP_BLOCKS; hipLaunchKernelGGL(HIP_KERNEL_NAME(tasgpu_dglo_eval_sharedpoints), num_blocks, _MAX_HIP_THREADS, 0, 0, dims, num_x, (int) map_tensor.size(), num_p, cache.data(), tensor_weights.data(), offset_per_level.data(), dim_offsets.data(), active_tensors.data(), active_num_points.data(), map_tensor.data(), map_index.data(), map_reference.data(), gpu_result); } template void TasGpu::devalglo(AccelerationContext const*, bool, bool, int, int, int, int, double const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, double*); template void TasGpu::devalglo(AccelerationContext const*, bool, bool, int, int, int, int, float const*, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, GpuVector const&, float*); void TasGpu::fillDataGPU(AccelerationContext const*, double value, long long n, long long stride, double data[]){ if (stride == 1){ ThreadGrid1d tgrid(n, _MAX_HIP_THREADS); hipLaunchKernelGGL(HIP_KERNEL_NAME(tascuda_vfill), tgrid.blocks, tgrid.threads, 0, 0, n, data, value); }else{ ThreadGrid1d tgrid(n, 32); hipLaunchKernelGGL(HIP_KERNEL_NAME(tascuda_sfill), tgrid.blocks, tgrid.threads, 0, 0, n, stride, data, value); } } } #endif TASMANIAN-8.1/SparseGrids/tsgIOHelpers.hpp000066400000000000000000000371331470551176200202230ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_IOHELPERS_HPP #define __TASMANIAN_IOHELPERS_HPP #include "tsgEnumerates.hpp" #include // put here because it causes a conflict with some versinos of CUDA (keep out of tsgAcceleratedStructures.hpp) /*! * \internal * \file tsgIOHelpers.hpp * \brief Templates to simply file I/O. * \author Miroslav Stoyanov * \ingroup TasmanianIO * * Several templates that simplify the I/O of Tasmanian. * Commonly used operations are lumped into templates with simple binary/ascii switch. * \endinternal */ /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianIO Templates for common I/O methods, simple binary/ascii switch provided for all templates * \endinternal */ namespace TasGrid{ /*! * \ingroup TasmanianSG * \brief Constant allowing for more expressive selection of ascii and binary mode in IO methods. */ constexpr bool mode_ascii = false; /*! * \ingroup TasmanianSG * \brief Constant allowing for more expressive selection of ascii and binary mode in IO methods. */ constexpr bool mode_binary = true; /*! * \internal * \ingroup TasmanianIO * \brief Collection of I/O handling templates. */ namespace IO{ /*! * \ingroup TasmanianIO * \brief Type indicating ascii I/O mode. */ struct mode_ascii_type{}; /*! * \ingroup TasmanianIO * \brief Type indicating binary I/O mode. */ struct mode_binary_type{}; /*! * \internal * \ingroup TasmanianIO * \brief Indicate the type of padding to use, none, space, new-line, etc. * * Ascii formats are human readable (for small data), but to achieve that * new lines and spaces must be added in the right place using the IOPad enumerate. * \endinternal */ enum IOPad{ //! \brief Do not add padding. pad_none, //! \brief Pad with space at the end. pad_rspace, //! \brief Pad with space at the beginning. pad_lspace, //! \brief Pad with new line. pad_line, //! \brief Pad with space if the flag is true, newline if false. pad_auto }; /*! * \ingroup TasmanianIO * \brief Creates a map with \b std::string rule names (used by C/Python/CLI) mapped to \b TypeOneDRule enums. */ inline std::map getStringRuleMap(){ return std::initializer_list>{ {"none", rule_none}, {"clenshaw-curtis", rule_clenshawcurtis}, {"clenshaw-curtis-zero", rule_clenshawcurtis0}, {"chebyshev", rule_chebyshev}, {"chebyshev-odd", rule_chebyshevodd}, {"gauss-legendre", rule_gausslegendre}, {"gauss-legendre-odd", rule_gausslegendreodd}, {"gauss-patterson", rule_gausspatterson}, {"leja", rule_leja}, {"leja-odd", rule_lejaodd}, {"rleja", rule_rleja}, {"rleja-double2", rule_rlejadouble2}, {"rleja-double4", rule_rlejadouble4}, {"rleja-odd", rule_rlejaodd}, {"rleja-shifted", rule_rlejashifted}, {"rleja-shifted-even", rule_rlejashiftedeven}, {"rleja-shifted-double", rule_rlejashifteddouble}, {"max-lebesgue", rule_maxlebesgue}, {"max-lebesgue-odd", rule_maxlebesgueodd}, {"min-lebesgue", rule_minlebesgue}, {"min-lebesgue-odd", rule_minlebesgueodd}, {"min-delta", rule_mindelta}, {"min-delta-odd", rule_mindeltaodd}, {"gauss-chebyshev1", rule_gausschebyshev1}, {"gauss-chebyshev1-odd", rule_gausschebyshev1odd}, {"gauss-chebyshev2", rule_gausschebyshev2}, {"gauss-chebyshev2-odd", rule_gausschebyshev2odd}, {"fejer2", rule_fejer2}, {"gauss-gegenbauer", rule_gaussgegenbauer}, {"gauss-gegenbauer-odd", rule_gaussgegenbauerodd}, {"gauss-jacobi", rule_gaussjacobi}, {"gauss-jacobi-odd", rule_gaussjacobiodd}, {"gauss-laguerre", rule_gausslaguerre}, {"gauss-laguerre-odd", rule_gausslaguerreodd}, {"gauss-hermite", rule_gausshermite}, {"gauss-hermite-odd", rule_gausshermiteodd}, {"custom-tabulated", rule_customtabulated}, {"localp", rule_localp}, {"localp-zero", rule_localp0}, {"localp-boundary", rule_localpb}, {"semi-localp", rule_semilocalp}, {"wavelet", rule_wavelet}, {"fourier", rule_fourier}}; } /*! * \ingroup TasmanianIO * \brief Map the string rule name to the enumerate, used in ASCII I/O, command line and Python. */ inline TypeOneDRule getRuleString(std::string const &name){ try{ return getStringRuleMap().at(name); }catch(std::out_of_range &){ return rule_none; } } /*! * \ingroup TasmanianIO * \brief Map the enumerate to a string, used in ASCII I/O, command line and Python. */ inline std::string getRuleString(TypeOneDRule rule){ auto smap = getStringRuleMap(); return std::find_if(smap.begin(), smap.end(), [&](std::pair r)->bool{ return (r.second == rule); })->first; } /*! * \ingroup TasmanianIO * \brief Creates a map with \b int (used by Fortran and binary I/O) mapped to \b TypeOneDRule enums. */ inline std::vector getIntRuleMap(){ return {rule_none, rule_clenshawcurtis, rule_clenshawcurtis0, rule_chebyshev, rule_chebyshevodd, rule_gausslegendre, rule_gausslegendreodd, rule_gausspatterson, rule_leja, rule_lejaodd, rule_rleja, rule_rlejadouble2, rule_rlejadouble4, rule_rlejaodd, rule_rlejashifted, rule_rlejashiftedeven, rule_rlejashifteddouble, rule_maxlebesgue, rule_maxlebesgueodd, rule_minlebesgue, rule_minlebesgueodd, rule_mindelta, rule_mindeltaodd, rule_gausschebyshev1, rule_gausschebyshev1odd, rule_gausschebyshev2, rule_gausschebyshev2odd, rule_fejer2, rule_gaussgegenbauer, rule_gaussgegenbauerodd, rule_gaussjacobi, rule_gaussjacobiodd, rule_gausslaguerre, rule_gausslaguerreodd, rule_gausshermite, rule_gausshermiteodd, rule_customtabulated, rule_localp, rule_localp0, rule_semilocalp, rule_wavelet, rule_fourier, rule_localpb}; } /*! * \ingroup TasmanianIO * \brief Map the int rule index to the enumerate, used in Fortran and binary IO. */ inline TypeOneDRule getRuleInt(int r){ auto rmap = getIntRuleMap(); return ((size_t) r < rmap.size()) ? rmap[(size_t) r] : rule_none; } /*! * \ingroup TasmanianIO * \brief Map the enumerate to an int, used in Fortran and binary IO. */ inline int getRuleInt(TypeOneDRule rule){ auto rmap = getIntRuleMap(); return (int) std::distance(rmap.begin(), std::find_if(rmap.begin(), rmap.end(), [&](TypeOneDRule r)->bool{ return (r == rule); })); } /*! * \ingroup TasmanianIO * \brief Creates a map with \b std::string rule names (used by C/Python/CLI) mapped to \b TypeDepth enums. */ inline std::map getStringToDepthMap(){ return std::initializer_list>{ {"level", type_level}, {"curved", type_curved}, {"iptotal", type_iptotal}, {"ipcurved", type_ipcurved}, {"qptotal", type_qptotal}, {"qpcurved", type_qpcurved}, {"hyperbolic", type_hyperbolic}, {"iphyperbolic", type_iphyperbolic}, {"qphyperbolic", type_qphyperbolic}, {"tensor", type_tensor}, {"iptensor", type_iptensor}, {"qptensor", type_qptensor}}; } /*! * \ingroup TasmanianIO * \brief Map the string to the enumerate multi-index selection strategy, used in command line and Python. */ inline TypeDepth getDepthTypeString(std::string const &name){ try{ return getStringToDepthMap().at(name); }catch(std::out_of_range &){ return type_none; } } /*! * \ingroup TasmanianIO * \brief Map the integer to the enumerate multi-index selection strategy, used in Fortran. */ inline TypeDepth getDepthTypeInt(int t){ std::vector imap = {type_none, type_level, type_curved, type_iptotal, type_ipcurved, type_qptotal, type_qpcurved, type_hyperbolic, type_iphyperbolic, type_qphyperbolic, type_tensor, type_iptensor, type_qptensor}; return ((size_t) t < imap.size()) ? imap[(size_t) t] : type_none; } /*! * \ingroup TasmanianIO * \brief Creates a map with \b std::string rule names (used by C/Python/CLI) mapped to \b TypeRefinement enums. */ inline std::map getStringToRefinementMap(){ return std::initializer_list>{ {"classic", refine_classic}, {"parents", refine_parents_first}, {"direction", refine_direction_selective}, {"fds", refine_fds}, {"stable", refine_stable}}; } /*! * \ingroup TasmanianIO * \brief Map the string to the enumerate hierarchical refinement strategy, used in command line and Python. */ inline TypeRefinement getTypeRefinementString(std::string const &name){ try{ return getStringToRefinementMap().at(name); }catch(std::out_of_range &){ return refine_none; } } /*! * \ingroup TasmanianIO * \brief Map the integer to the enumerate hierarchical refinement strategy, used by Fortran. */ inline TypeRefinement getTypeRefinementInt(int refinement){ std::vector imap = {refine_none, refine_classic, refine_parents_first, refine_direction_selective, refine_fds, refine_stable}; return ((size_t) refinement < imap.size()) ? imap[(size_t) refinement] : refine_none; } /*! * \ingroup TasmanianIO * \brief Write the flag to file, ascii uses 0 and 1, binary uses characters y and n (counter intuitive, I know). */ template void writeFlag(bool flag, std::ostream &os){ if (iomode == mode_ascii){ os << ((flag) ? "1" : "0"); if ((pad == pad_rspace) || ((pad == pad_auto) && flag)) os << " "; if ((pad == pad_line) || ((pad == pad_auto) && !flag)) os << std::endl; }else{ char cflag = ((flag) ? 'y' : 'n'); os.write(&cflag, sizeof(char)); } } /*! * \ingroup TasmanianIO * \brief Read a flag, ascii uses 0 and 1, binary uses characters y and n (counter intuitive, I know). */ template bool readFlag(std::istream &os){ if (std::is_same::value){ int flag; os >> flag; return (flag != 0); }else{ char cflag; os.read(&cflag, sizeof(char)); return (cflag == 'y'); } } /*! * \ingroup TasmanianIO * \brief Write the vector to the stream, the vector cannot be empty. */ template void writeVector(const std::vector &x, std::ostream &os){ if (iomode == mode_ascii){ if (pad == pad_lspace) for(auto i : x) os << " " << i; if (pad == pad_rspace) for(auto i : x) os << i << " "; if ((pad == pad_none) || (pad == pad_line)){ os << x[0]; for(size_t i = 1; i < x.size(); i++) os << " " << x[i]; if (pad == pad_line) os << std::endl; } }else{ os.write((char*) x.data(), x.size() * sizeof(VecType)); } } /*! * \ingroup TasmanianIO * \brief Read the vector from the stream, the size must already be set. */ template void readVector(std::istream &is, std::vector &x){ if (std::is_same::value){ for(auto &i : x) is >> i; }else{ is.read((char*) x.data(), x.size() * sizeof(VecType)); } } /*! * \ingroup TasmanianIO * \brief Read the vector with the specified size. */ template std::vector readVector(std::istream &is, SizeType num_entries){ std::vector x((size_t) num_entries); readVector(is, x); return x; } /*! * \ingroup TasmanianIO * \brief Write a bunch of numbers with the same type. */ template void writeNumbers(std::ostream &os, Vals... vals){ std::vector>::type> values = {vals...}; writeVector(values, os); } /*! * \ingroup TasmanianIO * \brief Read a single number, used to read ints (and potentially cast to size_t) or read a double. */ template Val readNumber(std::istream &is){ Val v; if (std::is_same::value){ is >> v; }else{ is.read((char*) &v, sizeof(Val)); } return v; } /*! * \ingroup TasmanianIO * \brief Write a rule. */ template void writeRule(TypeOneDRule rule, std::ostream &os){ if (iomode == mode_ascii){ os << getRuleString(rule) << std::endl; }else{ int r = getRuleInt(rule); os.write((char*) &r, sizeof(int)); } } /*! * \ingroup TasmanianIO * \brief Read a rule. */ template TypeOneDRule readRule(std::istream &is){ if (std::is_same::value){ std::string T; is >> T; return getRuleString(T); }else{ return getRuleInt(readNumber(is)); } } } } #endif TASMANIAN-8.1/SparseGrids/tsgIndexManipulator.cpp000066400000000000000000000675161470551176200216570ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_INDEX_MANIPULATOR_CPP #define __TSG_INDEX_MANIPULATOR_CPP #include "tsgIndexManipulator.hpp" namespace TasGrid{ namespace MultiIndexManipulations{ /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Generate a series of \b level_sets where each set has the parents/children of the previous one that satisfy the \b inside() criteria. * * On entry, \b level_sets must constain at least one set. * The function takes the last set in \b level_sets and adds a new set of * eithe the parents or children that also satisfy the \b inside() condition. * The process is repeated until the new set is empty. * \endinternal */ template void repeatAddIndexes(std::function &index)> inside, std::vector &level_sets){ size_t num_dimensions = level_sets.back().getNumDimensions(); bool adding = true; while(adding){ Data2D level((int) num_dimensions, 0); int num_indexes = level_sets.back().getNumIndexes(); #pragma omp parallel { std::vector point(num_dimensions); Data2D mlevel((int) num_dimensions, 0); #pragma omp for for(int i=0; i= 0) { bool is_inside = false; #pragma omp critical(level_append) { is_inside = inside(point); } if (is_inside) mlevel.appendStrip(point); } p -= (use_parents_direction) ? -1 : 1; // restore p } } #pragma omp critical { level.append(mlevel); } } adding = (level.getNumStrips() > 0); if (adding) level_sets.push_back(MultiIndexSet(level)); } } /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Retuns the union of all \b level_sets, all sets are destroyed in the process. * * \endinternal */ inline MultiIndexSet unionSets(std::vector &level_sets){ long long num_levels = level_sets.size(); while(num_levels > 1){ long long stride = num_levels / 2 + (((num_levels % 2) > 0) ? 1 : 0); #pragma omp parallel for for(long long i=0; i completion((int) num_dimensions, 0); #pragma omp parallel for for(int i=0; i point(num_dimensions); std::copy_n(set.getIndex(i), num_dimensions, point.data()); for(auto &p : point){ if (p != 0){ p--; if (set.missing(point)){ #pragma omp critical { completion.appendStrip(point); } } p++; } } } if (completion.getNumStrips() > 0){ std::vector level_sets = { MultiIndexSet(completion) }; constexpr bool use_parents = true; repeatAddIndexes([&](std::vector const &p) -> bool{ return set.missing(p); }, level_sets); set += unionSets(level_sets); } } /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Generate the minimum lower complete multi-index set that includes the indexes satisfying \b criteria(), assumes \b criteria() defines a connected set. * * \endinternal */ inline MultiIndexSet generateGeneralMultiIndexSet(size_t num_dimensions, std::function &index)> criteria){ std::vector level_sets = { MultiIndexSet(num_dimensions, std::vector(num_dimensions, 0)) }; constexpr bool use_parents = false; repeatAddIndexes(criteria, level_sets); MultiIndexSet set = unionSets(level_sets); completeSetToLower(set); return set; } /*! * \internal * \brief Generate the multi-index of indexes with weighs less than the \b normalized_offset. * * The weight of an index uses the \b weights combined with the \b rule_exactness(). * Called only when the set is guaranteed to be lower complete, * then the one dimensional weights can be cached prior to running the selection algorithm. * * If \b check_limits is \b false, then \b level_limits are ignored for speedup. * \endinternal */ template MultiIndexSet selectLowerSet(ProperWeights const &weights, std::function rule_exactness, int normalized_offset, std::vector const &level_limits){ size_t num_dimensions = weights.getNumDimensions(); if (weights.contour == type_level){ auto cache = generateLevelWeightsCache(weights, rule_exactness, normalized_offset); return generateLowerMultiIndexSet(num_dimensions, [&](std::vector const &index)->bool{ if (check_limits) for(size_t j=0; j -1) && (index[j] > level_limits[j])) return false; return (getIndexWeight(index.data(), cache) <= normalized_offset); }); }else if (weights.contour == type_curved){ auto cache = generateLevelWeightsCache(weights, rule_exactness, normalized_offset); double noff = (double) normalized_offset; return generateLowerMultiIndexSet(num_dimensions, [&](std::vector const &index)->bool{ if (check_limits) for(size_t j=0; j -1) && (index[j] > level_limits[j])) return false; return (std::ceil(getIndexWeight(index.data(), cache)) <= noff); }); }else{ // type_hyperbolic auto cache = generateLevelWeightsCache(weights, rule_exactness, normalized_offset); double noff = (double) normalized_offset; return generateLowerMultiIndexSet(num_dimensions, [&](std::vector const &index)->bool{ if (check_limits) for(size_t j=0; j -1) && (index[j] > level_limits[j])) return false; return (std::ceil(getIndexWeight(index.data(), cache)) <= noff); }); } } /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Generates the minimum lower complete set that contains all indexes with weights less than \b normalized_offset. * * The weight of an index uses the \b weights combined with the \b rule_exactness(). * Called only for contour \b type_curved and caches values on-the-fly. * * If \b check_limits is \b false, then \b level_limits are ignored for speedup. * \endinternal */ template MultiIndexSet selectGeneralSet(ProperWeights const &weights, std::function rule_exactness, int normalized_offset, std::vector const &level_limits){ size_t num_dimensions = weights.getNumDimensions(); std::vector> cache(num_dimensions); for(size_t j=0; j const &index) -> bool{ if (check_limits) for(size_t j=0; j level_limits[j]) return false; double w = 0; for(size_t j=0; j= (int) cache[j].size()){ int exactness = 1 + rule_exactness((int)(cache[j].size() - 1)); cache[j].push_back( (double) weights.linear[j] * exactness + weights.curved[j] * std::log1p((double) exactness) ); } w += cache[j][index[j]]; } return (std::ceil(w) <= noff); }); } MultiIndexSet selectTensors(size_t num_dimensions, int offset, TypeDepth type, std::function rule_exactness, std::vector const &anisotropic_weights, std::vector const &level_limits){ // special case of a full tensor selection if ((type == type_tensor) || (type == type_iptensor) || (type == type_qptensor)){ // special case, full tensor std::vector max_exactness = (anisotropic_weights.empty()) ? std::vector(num_dimensions, 1) : anisotropic_weights; for(auto &e : max_exactness) e *= offset; std::vector num_points(num_dimensions, 0); // how many points to have in each direction std::transform(max_exactness.begin(), max_exactness.end(), num_points.begin(), [&](int e)-> int{ int l = 0; // level while(rule_exactness(l) < e) l++; // get the first level that covers the weight return l+1; // adding extra one to change interpretation from 0-index "level" to 1-index "number of points" }); if (!level_limits.empty()){ for(size_t j=0; j= 0) num_points[j] = std::min(num_points[j], level_limits[j]+1); // the +1 indicates switch from max-level to number-of-points } return generateFullTensorSet(num_points); } ProperWeights weights(num_dimensions, type, anisotropic_weights); int normalized_offset = offset * weights.minLinear(); if (weights.provenLower()){ // if the set is guaranteed to be lower if (level_limits.empty()){ return selectLowerSet(weights, rule_exactness, normalized_offset, level_limits); }else{ return selectLowerSet(weights, rule_exactness, normalized_offset, level_limits); } }else{ if (level_limits.empty()){ return selectGeneralSet(weights, rule_exactness, normalized_offset, level_limits); }else{ return selectGeneralSet(weights, rule_exactness, normalized_offset, level_limits); } } } std::vector computeLevels(MultiIndexSet const &mset){ // cannot add as inline to the public header due to the pragma and possible "unknown pragma" message int num_indexes = mset.getNumIndexes(); size_t num_dimensions = mset.getNumDimensions(); std::vector levels((size_t) num_indexes); #pragma omp parallel for for(int i=0; i getMaxIndexes(const MultiIndexSet &mset){ size_t num_dimensions = mset.getNumDimensions(); std::vector max_index(num_dimensions, 0); int n = mset.getNumIndexes(); #pragma omp parallel { std::vector local_max_index(num_dimensions, 0); #pragma omp for for(int i=0; i computeDAGup(MultiIndexSet const &mset){ size_t num_dimensions = (size_t) mset.getNumDimensions(); int n = mset.getNumIndexes(); Data2D parents(mset.getNumDimensions(), n); #pragma omp parallel for schedule(static) for(int i=0; i dad(num_dimensions); std::copy_n(mset.getIndex(i), num_dimensions, dad.data()); int *v = parents.getStrip(i); for(auto &d : dad){ d--; *v = (d < 0) ? -1 : mset.getSlot(dad); d++; v++; } } return parents; } MultiIndexSet selectFlaggedChildren(const MultiIndexSet &mset, const std::vector &flagged, const std::vector &level_limits){ size_t num_dimensions = mset.getNumDimensions(); int n = mset.getNumIndexes(); Data2D children_unsorted(num_dimensions, 0); #ifdef _OPENMP #pragma omp parallel { Data2D lrefined(num_dimensions, 0); std::vector kid(num_dimensions); if (level_limits.empty()){ #pragma omp for for(int i=0; i kid(num_dimensions); if (level_limits.empty()){ for(int i=0; i getNumPoints){ size_t num_dimensions = (size_t) tensors.getNumDimensions(); std::vector delta_sets((size_t) tensors.getNumIndexes()); #pragma omp parallel for for(int i=0; i raw_points(num_dimensions, 0); std::vector num_points_delta(num_dimensions); std::vector offsets(num_dimensions); std::vector index(num_dimensions); const int *p = tensors.getIndex(i); size_t num_total = 1; for(size_t j=0; j 0){ offsets[j] = getNumPoints(p[j]-1); num_points_delta[j] -= offsets[j]; }else{ offsets[j] = 0; } num_total *= (size_t) num_points_delta[j]; } for(size_t k=0; k=0; j--){ index[j] = offsets[j] + (int) (t % num_points_delta[j]); t /= (size_t) num_points_delta[j]; } raw_points.appendStrip(index); } delta_sets[i] = MultiIndexSet(raw_points); } return unionSets(delta_sets); } MultiIndexSet generateNonNestedPoints(const MultiIndexSet &tensors, const OneDimensionalWrapper &wrapper){ size_t num_dimensions = tensors.getNumDimensions(); int num_tensors = tensors.getNumIndexes(); std::vector point_tensors((size_t) num_tensors); #pragma omp parallel for for(int t=0; t num_entries(num_dimensions); const int *p = tensors.getIndex(t); std::transform(p, p + num_dimensions, num_entries.begin(), [&](int l)->int{ return wrapper.getNumPoints(l); }); int num_total = 1; for(auto &l : num_entries) num_total *= l; Data2D raw_points(num_dimensions, num_total); auto iter = raw_points.rbegin(); for(int i=num_total-1; i>=0; i--){ int d = i; auto l = num_entries.rbegin(); // in order to generate indexes in the correct order, the for loop must go backwards for(size_t j = 0; j> &map, std::vector> &lines1d) { int num_dimensions = iset.getNumDimensions(); int num_tensors = iset.getNumIndexes(); int num_levels = 1 + *std::max_element(iset.begin(), iset.end()); auto match_outside_dim = [&](int d, int const*a, int const *b) -> bool { for(int j=0; j>(num_dimensions, std::vector(num_tensors)); lines1d = std::vector>(num_dimensions); for(auto &ji : lines1d) ji.reserve(num_levels); #pragma omp parallel for for(int d=0; dbool{ const int * idxa = iset.getIndex(a); const int * idxb = iset.getIndex(b); for(int j=0; j idxb[j]) return false; } } // lexigographical order, dimension d is the fastest moving one if (idxa[d] < idxb[d]) return true; if (idxa[d] > idxb[d]) return false; return false; }); } if (num_dimensions == 1) { lines1d[d].push_back(0); lines1d[d].push_back(num_tensors); } else { int const *c_index = iset.getIndex(map[d][0]); lines1d[d].push_back(0); for(int i=1; i computeTensorWeights(MultiIndexSet const &mset){ int num_dimensions = mset.getNumDimensions(); int num_tensors = mset.getNumIndexes(); if (num_dimensions == 1) { std::vector weights(num_tensors, 0); weights.back() = 1; return weights; } std::vector> map; std::vector> lines1d; resortIndexes(mset, map, lines1d); Data2D dag_down(num_dimensions, num_tensors); std::vector weights(num_tensors, 0); // the row with contiguous indexes has a trivial solution auto const& last_jobs = lines1d[num_dimensions-1]; for(int i=0; i(last_jobs.size() - 1); i++) weights[last_jobs[i+1] - 1] = 1; for(int d=num_dimensions-2; d>=0; d--) { #pragma omp parallel for for(int job = 0; job < static_cast(lines1d[d].size() - 1); job++) { for(int i=lines1d[d][job+1]-2; i>=lines1d[d][job]; i--) { int &val = weights[map[d][i]]; for(int j=i+1; j exactness){ size_t num_dimensions = (size_t) tensors.getNumDimensions(); int num_tensors = tensors.getNumIndexes(); std::vector polynomial_tensors((size_t) num_tensors); #pragma omp parallel for for(int i=0; i npoints(num_dimensions); const int *p = tensors.getIndex(i); for(size_t j=0; j inferAnisotropicWeights(AccelerationContext const *acceleration, TypeOneDRule rule, TypeDepth depth, MultiIndexSet const &points, std::vector const &coefficients, double tol){ int num_dimensions = static_cast(points.getNumDimensions()); int cols = (OneDimensionalMeta::getControurType(depth) == type_curved) ? 2 * num_dimensions + 1 : num_dimensions + 1; int data_rows = static_cast(std::count_if(coefficients.begin(), coefficients.end(), [=](double c)->bool{ return (std::abs(c) > tol); })); Data2D A(data_rows + cols, cols, 0.0); std::vector b(data_rows + cols, 0.0); int c = 0; for(int i=0; i tol){ int const *indx = points.getIndex(i); for(int j=0; j(indx[j]); } A.getStrip(cols-1)[c] = 1.0; b[c++] = -std::log(std::abs(coefficients[i])); } } if (rule == rule_fourier){ for(int j=0; j((static_cast(cc[i]) + 1) / 2); } } if (OneDimensionalMeta::getControurType(depth) == type_hyperbolic){ for(int j=0; j x(cols); TasmanianDenseSolver::solveLeastSquares(acceleration, data_rows + cols, cols, A.getStrip(0), b.data(), x.data()); std::vector weights(cols - 1); for(size_t j=0; j(x[j] * 1000.0 + 0.5); int max_weight = *std::max_element(weights.begin(), weights.begin() + num_dimensions); if (max_weight <= 0){ // all directions are diverging, default to isotropic total degree std::fill_n(weights.begin(), num_dimensions, 1); if (OneDimensionalMeta::getControurType(depth) == type_curved) std::fill(weights.begin() + num_dimensions, weights.end(), 0); }else{ int min_weight = max_weight; for(int j=0; j 0 and weights[j] < min_weight) min_weight = weights[j]; // find the smallest positive weight for(int j=0; j weights[j]) weights[num_dimensions + j] = (weights[j] > 0.0) ? weights[num_dimensions + j] : -weights[num_dimensions + j]; } } } } return weights; } } // MultiIndexManipulations } // TasGrid #endif TASMANIAN-8.1/SparseGrids/tsgIndexManipulator.hpp000066400000000000000000000635601470551176200216570ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_INDEX_MANIPULATOR_HPP #define __TSG_INDEX_MANIPULATOR_HPP #include "tsgIndexSets.hpp" #include "tsgOneDimensionalWrapper.hpp" /*! * \internal * \file tsgIndexManipulator.hpp * \brief Algorithms for manipulating sets of multi-indexes. * \author Miroslav Stoyanov * \ingroup TasmanianMultiIndexManipulations * * A series of templates, lambda, and regular functions that allow the manipulation of * multi-indexes and sets of multi-indexes. * \endinternal */ /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianMultiIndexManipulations Multi-Index manipulation algorithms * * \par Multi-Index manipulation algorithms * A series of templates, lambda, and regular functions that allow the manipulation of * multi-indexes and sets of multi-indexes. The algorithms include the selection of * multi-indexes according to a criteria, union of a vector of multi-index sets, * normalization of anisotropic weights, map parents and children within a set (which * generates a DAG structure), complete a set to satisfy the lower-property, etc. * \endinternal */ namespace TasGrid{ /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Collection of algorithm to manipulate multi-indexes. */ namespace MultiIndexManipulations{ /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Create a full-tensor multi-index set with \b num_entries in each direction. * * \endinternal */ inline MultiIndexSet generateFullTensorSet(std::vector const &num_entries){ size_t num_dimensions = num_entries.size(); int num_total = 1; for(auto &l : num_entries) num_total *= l; std::vector indexes(Utils::size_mult(num_dimensions, num_total)); auto iter = indexes.rbegin(); for(int i=num_total-1; i>=0; i--){ int t = i; auto l = num_entries.rbegin(); // in order to generate indexes in the correct order, the for loop must go backwards for(size_t j = 0; j &index)> inside){ size_t c = num_dimensions -1; bool is_in = true; std::vector root(num_dimensions, 0); std::vector indexes; while(is_in || (c > 0)){ if (is_in){ indexes.insert(indexes.end(), root.begin(), root.end()); c = num_dimensions-1; root[c]++; }else{ std::fill(root.begin() + c, root.end(), 0); root[--c]++; } is_in = inside(root); } return MultiIndexSet(num_dimensions, std::move(indexes)); } /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Expand the \b set with the minimum number of multi-indexes that will result in a lower complete set. * \endinternal */ void completeSetToLower(MultiIndexSet &set); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Holds anisotropic weights in a usable format. * * The external API accepts weigths as a single vector of integers or even an empty vector, * the \b ProperWeights holds weights that are always defined in a form suitable for computing. * \endinternal */ struct ProperWeights{ //! \brief Interpret the single vector and form the proper weights, e.g., use defaults, scale hyperbolic weights, split \b type_ipcurved into linear and curved, etc. ProperWeights(size_t num_dimensions, TypeDepth type, std::vector const &weights){ contour = OneDimensionalMeta::getControurType(type); if (weights.empty()) linear = std::vector(num_dimensions, 1); if (contour == type_level){ // linear weights only if (!weights.empty()){ linear = weights; // simplest type } }else if (contour == type_curved){ if (weights.empty()){ curved = std::vector(num_dimensions, 0.0); // cannot define default log-correction }else{ linear = std::vector(weights.begin(), weights.begin() + num_dimensions); curved = std::vector(num_dimensions); std::transform(weights.begin() + num_dimensions, weights.end(), curved.begin(), [&](int i)->double{ return (double) i; }); } }else{ // hyperbolic if (weights.empty()){ curved = std::vector(num_dimensions, 1.0); }else{ linear = std::vector(num_dimensions, 1); // used only for offset normalization double exponent_normalization = (double) *std::min_element(weights.begin(), weights.end()); curved = std::vector(num_dimensions); std::transform(weights.begin(), weights.end(), curved.begin(), [&](int i)->double{ return ((double) i) / exponent_normalization; }); } } } //! \brief Return \b true if the combination of weights and contour is guaranteed to give a lower-complete set. bool provenLower() const{ if (contour == type_curved) for(size_t i=0; i linear; //! \brief The curved components of the weights \b type_curved contours; a scaled vector of exponents for \b type_hyperbolic; empty for \b type_level. std::vector curved; }; /*! * \internal * \brief Generate weights cache for the given parameters. * * Complexity chosen here in favor of performance and re-usability. * - \b isotropic indicates whether to treat the \b offset as a maximum cache size in each direction (\b true) * of as a cut-off for the weights, i.e., cache until the 1-D weight exceeds the offset. * - \b weights.contour must match \b contour * - if \b contour is \b type_level, then \b CacheType must be \b int * - if \b contour is \b type_curved or \b type_hyperbolic, then \b CacheType must be \b double * \endinternal */ template std::vector> generateLevelWeightsCache(ProperWeights const &weights, std::function rule_exactness, int offset){ size_t num_dimensions = weights.getNumDimensions(); std::vector> cache(num_dimensions); std::vector exactness_cache; // if we know the sized here, then assign, otherwise dynamically build later if (isotropic){ for(auto &vec : cache) vec.reserve((size_t) offset); exactness_cache.resize((size_t) offset); exactness_cache[0] = 0; for(int i=1; i= exactness_cache.size())) exactness_cache.push_back(1 + rule_exactness((int)(i - 1))); int e = exactness_cache[i]; if (contour == type_level){ w = (CacheType)(wl * e); }else if (contour == type_curved){ w = (CacheType)(wl * e) + (CacheType)(wc * std::log1p((CacheType)e)); }else{ // must be hyperbolic w = (CacheType)(pow((CacheType) (1 + e), wc)); } cache[j].push_back(w); // isotropic mode works until offset, anisotropic mode works until weight reaches the offset }while( (!isotropic && (std::ceil(w) <= (CacheType) offset)) || (isotropic && (i + 1 < (size_t) offset)) ); } return cache; } /*! * \internal * \brief Returns the weight for the multi-index using the cache, assuming level contour. * * \endinternal */ template inline CacheType getIndexWeight(int const index[], std::vector> const &cache){ CacheType w = (contour == type_hyperbolic) ? 1 : 0; for(size_t j=0; j rule_exactness, std::vector const &anisotropic_weights, std::vector const &level_limits); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Returns a vector that is the sum of entries of each multi-index in the set. * * \endinternal */ std::vector computeLevels(MultiIndexSet const &mset); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Returns a vector with the maximum index in each dimension. * * \endinternal */ std::vector getMaxIndexes(const MultiIndexSet &mset); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Returns a Data2D structure where each strip holds the slot-index of the parents of indexes in \b mset (for each direction), using one-point-growth hierarchy. * * Adds -1 in places where the parents are missing. * \endinternal */ Data2D computeDAGup(MultiIndexSet const &mset); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Using the \b flagged map, create a set with the flagged children of \b mset but only if they obey the \b level_limits. * * \endinternal */ MultiIndexSet selectFlaggedChildren(const MultiIndexSet &mset, const std::vector &flagged, const std::vector &level_limits); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Converts a set of nested \b tensors to the actual points, where each level has \b getNumPoints() in each direction. * * Working with nested points, it is more efficient to interpret the tensors as a surplus operators and generate only the surplus points; * then take the union without repeated indexes. * This can work if and only if \b tensors is a lower-complete set, i.e., the \b tensors in \b GridGlobal and not the active_tensors. * \endinternal */ MultiIndexSet generateNestedPoints(const MultiIndexSet &tensors, std::function getNumPoints); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Converts a set of non-nested active \b tensors to the actual points, the \b wrapper gives mapping between level and point indexes. * * For each index in \b tensor, generate a local set of points and then remap them to the global index using the \b wrapper.getPointIndex(). * \endinternal */ MultiIndexSet generateNonNestedPoints(const MultiIndexSet &tensors, const OneDimensionalWrapper &wrapper); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Creates a map with sorted indexes dimension by dimension. * * \param iset is a non-empty set of indexes * \param map (output) the i-th index in the order with d as the fastest changing (contiguous) dimension is map[d][i] * \param lines1d for each dimension d the indexes that match in all but d-dimension will be between * lines1d[d][i] and lines1d[d][i+1] (not including the last entry) * This is similar to the pntr index of row-compressed sparse matrix * \endinternal */ void resortIndexes(const MultiIndexSet &iset, std::vector> &map, std::vector> &lines1d); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Find the indexes of all points associated with the tensor with \b levels within the global \b points set. * * The order in which the tensors are formed here must match the order in which they will be used, * e.g., when computing interpolation and quadrature weights. */ template std::vector referencePoints(const int levels[], const OneDimensionalWrapper &wrapper, const MultiIndexSet &points){ size_t num_dimensions = (size_t) points.getNumDimensions(); std::vector num_points(num_dimensions); int num_total = 1; // this will be a subset of all points, no danger of overflow for(size_t j=0; j refs(num_total); std::vector p(num_dimensions); for(int i=0; i=0; j--){ p[j] = (nested) ? t % *n : wrapper.getPointIndex(levels[j], t % *n); t /= *n++; } refs[i] = points.getSlot(p); } return refs; } /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Computes the weights for the tensor linear combination, \b mset must be a lower complete set. * * \endinternal */ std::vector computeTensorWeights(MultiIndexSet const &mset); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Creates a set containing only the entries of \b mset that have non-zero \b weights. * * \endinternal */ inline MultiIndexSet createActiveTensors(const MultiIndexSet &mset, const std::vector &weights){ size_t num_dimensions = mset.getNumDimensions(); size_t nz_weights = 0; for(auto w: weights) if (w != 0) nz_weights++; std::vector indexes(nz_weights * num_dimensions); nz_weights = 0; auto iter = indexes.begin(); auto iset = mset.begin(); for(auto w: weights){ if (w != 0){ std::copy_n(iset, num_dimensions, iter); std::advance(iter, num_dimensions); } std::advance(iset, num_dimensions); } return MultiIndexSet(num_dimensions, std::move(indexes)); } /*! * \ingroup TasmanianMultiIndexManipulations * \brief Uses the computeTensorWeights() and createActiveTensors() to extract the active tensors and the active (non-zero) weights. */ inline void computeActiveTensorsWeights(MultiIndexSet const &tensors, MultiIndexSet &active_tensors, std::vector &active_w){ std::vector tensors_w = MultiIndexManipulations::computeTensorWeights(tensors); active_tensors = MultiIndexManipulations::createActiveTensors(tensors, tensors_w); active_w = std::vector(); active_w.reserve(active_tensors.getNumIndexes()); for(auto w : tensors_w) if (w != 0) active_w.push_back(w); } /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief For a set of \b tensors compute the corresponding polynomial space assuming the 1D rules have given \b exactness(). * * \endinternal */ MultiIndexSet createPolynomialSpace(const MultiIndexSet &tensors, std::function exactness); /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Assuming that \b mset is lower complete, return \b true if adding the \b point will preserve completeness. * * \param point is the new point to add to an existing set * \param mset is an existing lower complete set * \param scratch is scratch space, must have size equal to point.size() and will be used for temporary storage * the scratch reduces allocations * * \endinternal */ inline bool isLowerComplete(std::vector const &point, MultiIndexSet const &mset, std::vector &scratch){ std::copy(point.begin(), point.end(), scratch.begin()); for(int &d : scratch){ if (d > 0){ d--; if (mset.missing(scratch)) return false; d++; } } return true; } /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief Return the largest subset of \b candidates such that adding it to \b current will preserve lower completeness. * * \endinternal */ inline MultiIndexSet getLargestCompletion(MultiIndexSet const ¤t, MultiIndexSet const &candidates){ if (candidates.empty()) return MultiIndexSet(); auto num_dimensions = candidates.getNumDimensions(); MultiIndexSet result; // start with an empty set if (current.empty()){ if (candidates.missing(std::vector(num_dimensions, 0))){ return MultiIndexSet(); // current is empty, 0-th index is the only thing that can be added }else{ result = MultiIndexSet(num_dimensions, std::vector(num_dimensions, 0)); } } std::vector scratch(num_dimensions); bool loopon = true; while(loopon){ Data2D update(num_dimensions, 0); MultiIndexSet total = current; if (!result.empty()) total += result; for(int i=0; i kid(total.getIndex(i), total.getIndex(i) + num_dimensions); for(int &k : kid){ k++; // construct the kid in the new direction if (!candidates.missing(kid) && result.missing(kid) && isLowerComplete(kid, total, scratch)) update.appendStrip(kid); k--; } } loopon = (update.getNumStrips() > 0); if (loopon) result += update; } return result; } /*! * \internal * \ingroup TasmanianMultiIndexManipulations * \brief For a set of \b tensors create an \b mset that contain the children of indexes in \b tensors that are missing from \b exclude and obey the \b level_limits. * * If \b limited is \b false, then the \b level_limits are ignored. * \endinternal */ template MultiIndexSet addExclusiveChildren(const MultiIndexSet &tensors, const MultiIndexSet &exclude, const std::vector level_limits){ int num_dimensions = (int) tensors.getNumDimensions(); Data2D tens(num_dimensions, 0); std::vector scratch(num_dimensions); for(int i=0; i kid(t, t + num_dimensions); auto ilimit = level_limits.begin(); for(auto &k : kid){ k++; if (exclude.missing(kid) && tensors.missing(kid)){ // if the kid is not to be excluded and if not included in the current set if (isLowerComplete(kid, tensors, scratch)){ if (limited){ if ((*ilimit == -1) || (k <= *ilimit)) tens.appendStrip(kid); ilimit++; }else{ tens.appendStrip(kid); } } } k--; } } return MultiIndexSet(tens); } /*! * \ingroup TasmanianMultiIndexManipulations * \brief Converts int-indexes to double-valued abscissas using the provided rule. * * Nodes of the sparse grid are stored as multi-indexes in either vectors or MultiIndexSet classes. * The nodes are converted to double precision numbers according to a specified one-dimensional rule. * * \tparam IndexList is either a MultiIndexSet or a std::vector, both of which have a begin and end methods, * the begin and end must allow iteration over a range of integers. * \tparam RuleLike is either a OneDimensionalWrapper, derived from BaseRuleLocalPolynomial, or RuleWavelet, * or any other class with getNode method that converts an int to a double; * GridSequence class provides the getNode() method too. * \tparam OutputIteratorLike indicates where the write the output, e.g., an iterator or an array, * the output matches with OutputIteratorLike as defined by std::transform. * * \param list defines a range of integers to be converted to double precision numbers. * \param rule is a class with getNode method that defines the conversion. * \param nodes marks the beginning of the output range. * * \returns OutputIteratorLike at the end of the range that has been written. * * Overloads are provided that work with an \b ibegin iterator and a number of \b entries in place of the \b list, * as well as returning the result in a std::vector as opposed to writing to a \b nodes iterator. * See the brief descriptions at the top of the page. */ template OutputIteratorLike indexesToNodes(IndexList const &list, RuleLike const &rule, OutputIteratorLike nodes){ return std::transform(list.begin(), list.end(), nodes, [&](int i)->double{ return rule.getNode(i); }); } /*! * \ingroup TasmanianMultiIndexManipulations * \brief Overload that uses a begin and a number of entries. */ template OutputIteratorLike indexesToNodes(IteratorLike ibegin, size_t num_entries, RuleLike const &rule, OutputIteratorLike nodes){ return std::transform(ibegin, ibegin + num_entries, nodes, [&](int i)->double{ return rule.getNode(i); }); } /*! * \ingroup TasmanianMultiIndexManipulations * \brief Overload that returns the result in a vector. */ template std::vector getIndexesToNodes(IndexList const &list, RuleLike const &rule){ std::vector result(std::distance(list.begin(), list.end())); indexesToNodes(list, rule, result.begin()); return result; } /*! * \ingroup TasmanianMultiIndexManipulations * \brief Overload that returns the result in a vector. */ template std::vector getIndexesToNodes(IteratorLike ibegin, size_t num_entries, RuleLike const &rule){ std::vector result(num_entries); indexesToNodes(ibegin, num_entries, rule, result.begin()); return result; } /*! * \ingroup TasmanianMultiIndexManipulations * \brief Overload that returns the result in a vector. * * Infers the weights that best describe the decay-rate of the normalized coefficients given the rule and depth. * The points represent either the polynomial powers of the frequencies of the Fourier transform and tol is the * cutoff tolerance, i.e., use only the coefficients with magnitude exceeding tol. */ std::vector inferAnisotropicWeights(AccelerationContext const *acceleration, TypeOneDRule rule, TypeDepth depth, MultiIndexSet const &points, std::vector const &coefficients, double tol); } } #endif TASMANIAN-8.1/SparseGrids/tsgIndexSets.cpp000066400000000000000000000270001470551176200202620ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_INDEX_SETS_CPP #define __TASMANIAN_SPARSE_GRID_INDEX_SETS_CPP #include "tsgIndexSets.hpp" namespace TasGrid{ template void MultiIndexSet::write(std::ostream &os) const{ if (cache_num_indexes > 0){ IO::writeNumbers(os, static_cast(num_dimensions), cache_num_indexes); IO::writeVector(indexes, os); }else{ IO::writeNumbers(os, static_cast(num_dimensions), cache_num_indexes); } } template void MultiIndexSet::write(std::ostream &) const; // instantiate for faster build template void MultiIndexSet::write(std::ostream &) const; void MultiIndexSet::addSortedIndexes(const std::vector &addition){ if (indexes.empty()){ indexes = addition; }else{ std::vector old_indexes = std::move(indexes); indexes = std::vector(); // reset the indexes std::vector::const_iterator> merge_map; merge_map.reserve(addition.size() + old_indexes.size()); auto next = std::back_inserter(merge_map); auto compare = [&](std::vector::const_iterator ia, std::vector::const_iterator ib) -> TypeIndexRelation{ for(size_t j=0; j *ib++) return type_bbeforea; } return type_asameb; }; // merge with three way compare auto ia = old_indexes.begin(); auto ib = addition.begin(); auto aend = old_indexes.end(); auto bend = addition.end(); while((ia != aend) || (ib != bend)){ TypeIndexRelation relation; if (ib == bend){ relation = type_abeforeb; }else if (ia == aend){ relation = type_bbeforea; }else{ relation = compare(ia, ib); } if (relation == type_bbeforea){ next = ib; std::advance(ib, num_dimensions); }else{ next = ia; std::advance(ia, num_dimensions); if (relation == type_asameb) std::advance(ib, num_dimensions); } } indexes.resize(merge_map.size() * num_dimensions); // merge map will reference only indexes in both sets auto iindexes = indexes.begin(); for(auto &i : merge_map){ std::copy_n(i, num_dimensions, iindexes); std::advance(iindexes, num_dimensions); } } cache_num_indexes = (int) (indexes.size() / num_dimensions); } MultiIndexSet::MultiIndexSet(Data2D const &data) : num_dimensions((size_t) data.getStride()), cache_num_indexes(0){ size_t num = (size_t) data.getNumStrips(); if (num == 0) return; // nothing to do std::vector::const_iterator> index_refs(num); auto iadd = data.begin(); for(auto &i : index_refs){ i = iadd; std::advance(iadd, num_dimensions); } std::sort(index_refs.begin(), index_refs.end(), [&](std::vector::const_iterator ia, std::vector::const_iterator ib) -> bool{ for(size_t j=0; j *ib++) return false; } return false; }); auto unique_end = std::unique(index_refs.begin(), index_refs.end(), [&](std::vector::const_iterator ia, std::vector::const_iterator ib) -> bool{ for(size_t j=0; j TypeIndexRelation{ for(size_t j=0; j b[j]) return type_bbeforea; } return type_asameb; }(&(indexes[(size_t) current * num_dimensions]), p); if (t == type_abeforeb){ sstart = current+1; }else if (t == type_bbeforea){ send = current-1; }else{ return current; }; current = (sstart + send) / 2; } return -1; } MultiIndexSet MultiIndexSet::operator -(const MultiIndexSet &substract) const{ std::vector::const_iterator> kept_indexes; auto ithis = indexes.begin(); auto endthis = indexes.end(); auto iother = substract.begin(); auto endother = substract.end(); while(ithis != endthis){ if (iother == endother){ kept_indexes.push_back(ithis); std::advance(ithis, num_dimensions); }else{ TypeIndexRelation t = [&](std::vector::const_iterator ia, std::vector::const_iterator ib) -> TypeIndexRelation{ for(size_t j=0; j *ib++) return type_bbeforea; } return type_asameb; }(ithis, iother); if (t == type_abeforeb){ kept_indexes.push_back(ithis); std::advance(ithis, num_dimensions); }else{ std::advance(iother, num_dimensions); if (t == type_asameb) std::advance(ithis, num_dimensions); } } } if (kept_indexes.size() > 0){ std::vector new_indexes(num_dimensions * kept_indexes.size()); auto inew = new_indexes.begin(); for(auto i : kept_indexes){ std::copy_n(i, num_dimensions, inew); std::advance(inew, num_dimensions); } return MultiIndexSet(num_dimensions, std::move(new_indexes)); } return MultiIndexSet(); } void MultiIndexSet::removeIndex(const std::vector &p){ int slot = getSlot(p); if (slot > -1){ indexes.erase(indexes.begin() + static_cast(slot) * num_dimensions, indexes.begin() + static_cast(slot) * num_dimensions + num_dimensions); cache_num_indexes--; } } template void StorageSet::write(std::ostream &os) const{ IO::writeNumbers(os, static_cast(num_outputs), static_cast(num_values)); IO::writeFlag((values.size() != 0), os); if (values.size() != 0) IO::writeVector(values, os); } template void StorageSet::write(std::ostream &) const; template void StorageSet::write(std::ostream &) const; void StorageSet::addValues(const MultiIndexSet &old_set, const MultiIndexSet &new_set, const double new_vals[]){ int num_old = old_set.getNumIndexes(); int num_new = new_set.getNumIndexes(); size_t num_dimensions = old_set.getNumDimensions(); num_values += (size_t) num_new; std::vector combined_values(num_values * num_outputs); int iold = 0, inew = 0; size_t off_vals = 0; auto ivals = values.begin(); auto icombined = combined_values.begin(); auto compareIndexes = [&](int const a[], int const b[])-> TypeIndexRelation{ for(size_t j=0; j b[j]) return type_bbeforea; } return type_asameb; }; for(size_t i=0; i= num_old){ relation = type_abeforeb; }else if (inew >= num_new){ relation = type_bbeforea; }else{ relation = compareIndexes(new_set.getIndex(inew), old_set.getIndex(iold)); } if (relation == type_abeforeb){ std::copy_n(&(new_vals[off_vals]), num_outputs, icombined); inew++; off_vals += num_outputs; }else{ std::copy_n(ivals, num_outputs, icombined); iold++; std::advance(ivals, num_outputs); } std::advance(icombined, num_outputs); } std::swap(values, combined_values); } } #endif TASMANIAN-8.1/SparseGrids/tsgIndexSets.hpp000066400000000000000000000506631470551176200203020ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_INDEX_SETS_HPP #define __TASMANIAN_SPARSE_GRID_INDEX_SETS_HPP #include "tsgIOHelpers.hpp" /*! * \internal * \file tsgIndexSets.hpp * \brief Data structures for storing multi-indexes and floating point values. * \author Miroslav Stoyanov * \ingroup TasmanianSets * * Three classes for storage and easy access to multi-indexes and floating point values. * The majority of internal data-structures associated with the five types of grids * can be represented as two-dimensional data (or array/list of tuples), the three * classes here correspond to sorted or unsorted, integer or floating point data. * \endinternal */ /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianSets Multi-Index data structures * * \par Fundamental data structures * Three classes for storage and easy access to multi-indexes and floating point values. * The majority of internal data-structures associated with the five types of grids * can be represented as two-dimensional data (or array/list of tuples), the three * classes here correspond to sorted or unsorted, integer or floating point data. * \endinternal */ namespace TasGrid{ /*! * \internal * \ingroup TasmanianSets * \brief Take a vector logically organized into stips and strides and extract a sub-strip from every strip. * * Used in copy subset of the values and the Data2D surplusses. * The vector is organized in strips with the given \b stride * and the returned vector has the same number of strips * but containing the data between the \b ibegin and \b iend (not including \b iend). * \endinternal */ template std::vector spltVector2D(std::vector const &x, size_t stride, int ibegin, int iend){ size_t sbegin(ibegin), send(iend); size_t num_strips = x.size() / stride; size_t new_stride = send - sbegin; std::vector result(num_strips * new_stride); auto ix = x.begin(); auto ir = result.begin(); for(size_t i=0; i class Data2D{ public: //! \brief Default constructor makes an empty data-structure. Data2D() : stride(0), num_strips(0){} //! \brief Create data-structure with given \b stride and number of \b strips. template Data2D(IntTypeA new_stride, IntTypeB new_num_strips) : stride(static_cast(new_stride)), num_strips(static_cast(new_num_strips)), vec(Utils::size_mult(stride, num_strips)){} //! \brief Create data-structure with given \b stride and number of \b strips and initializes with \b val. template Data2D(IntTypeA new_stride, IntTypeB new_num_strips, T val) : stride(static_cast(new_stride)), num_strips(static_cast(new_num_strips)), vec(Utils::size_mult(stride, num_strips), val){} //! \brief Create data-structure with given \b stride and number of \b strips and moves \b data into the internal vector. template Data2D(IntTypeA new_stride, IntTypeB new_num_strips, std::vector &&data) : stride(static_cast(new_stride)), num_strips(static_cast(new_num_strips)), vec(std::forward>(data)){} //! \brief Default destructor. ~Data2D() = default; //! \brief Write the internal vector to a stream. template void writeVector(std::ostream &os) const{ IO::writeVector(vec, os); } //! \brief Returns \b true if the number of strips is zero. bool empty() const{ return (num_strips == 0); } //! \brief Get the data between \b ibegin and \b iend of each strip. Data2D splitData(int ibegin, int iend) const{ if (stride == 0) return Data2D(); // empty data object Data2D result(iend - ibegin, 0); result.num_strips = num_strips; result.vec = spltVector2D(vec, stride, ibegin, iend); return result; } //! \brief Returns a reference to the \b i-th strip. T* getStrip(int i){ return &(vec[i*stride]); } //! \brief Returns a const reference to the \b i-th strip. T const* getStrip(int i) const{ return &(vec[i*stride]); } //! \brief Return iterator set at the \b i-th strip. typename std::vector::iterator getIStrip(int i){ return vec.begin() + Utils::size_mult(stride, i); } //! \brief Returns the stride. size_t getStride() const{ return stride; } //! \brief Returns the number of strips. int getNumStrips() const{ return (int) num_strips; } //! \brief Returns the total number of entries, stride times number of trips. size_t getTotalEntries() const{ return vec.size(); } //! \brief Returns a reference to the internal data. T* data(){ return vec.data(); } //! \brief Returns a const reference to the internal data. T const* data() const{ return vec.data(); } //! \brief Clear all used data. void clear(){ stride = 0; num_strips = 0; vec = std::vector(); } //! \brief Moves the data vector out of the class, this method invalidates the object. inline typename std::vector release(){ return std::move(vec); } //! \brief Returns an iterator to the beginning of the internal data inline typename std::vector::iterator begin(){ return vec.begin(); } //! \brief Returns a const iterator to the beginning of the internal data inline typename std::vector::const_iterator begin() const{ return vec.cbegin(); } //! \brief Returns an iterator to the end of the internal data inline typename std::vector::iterator end(){ return vec.end(); } //! \brief Returns a const iterator to the end of the internal data inline typename std::vector::const_iterator end() const{ return vec.cend(); } //! \brief Returns a reverse iterator to the end of the internal data inline typename std::vector::reverse_iterator rbegin(){ return vec.rbegin(); } //! \brief Uses std::vector::insert to append the data. void appendStrip(typename std::vector::const_iterator const &x){ vec.insert(vec.end(), x, x + stride); num_strips++; } //! \brief Uses std::vector::insert to append \b x, assumes \b x.size() is one stride. void appendStrip(const std::vector &x){ appendStrip(x.begin()); } //! \brief Uses std::vector::insert to append a strip \b x to the existing data at position \b pos, assumes \b x.size() is one stride. void appendStrip(int pos, const std::vector &x){ vec.insert(vec.begin() + static_cast(pos) * stride, x.begin(), x.end()); num_strips++; } //! \brief Uses std::vector::insert to append all the data from the other to this void append(Data2D const &other) { vec.insert(vec.end(), other.vec.begin(), other.vec.end()); num_strips += other.num_strips; } private: size_t stride, num_strips; std::vector vec; }; namespace IO{ /*! * \internal * \ingroup TasmanianIO * \brief Read the Data2D structure from the stream, assumes the given number of strips and stride. * * \endinternal */ template Data2D readData2D(std::istream &is, IndexStride stride, IndexNumStrips num_strips){ return Data2D(stride, num_strips, readVector(is, Utils::size_mult(stride, num_strips))); } } /*! * \internal * \ingroup TasmanianSets * \brief Class that stores multi-indexes in sorted (lexicographical) order. * * At the core of each sparse grid, there are multiple multi-index sets. * The organization of the data is similar to the \b Data2D class, but at any time the indexes * are stored in a lexicographical order. The main functionality provided here is: * - fast O(log(n)) search utilizing the lexicographical order * - synchronization between multi-indexes and values (i.e., model outputs) * - adding or removing indexes while preserving the order * - basic file I/O * \endinternal */ class MultiIndexSet{ public: //! \brief Default constructor, makes an empty set. MultiIndexSet() : num_dimensions(0), cache_num_indexes(0){} //! \brief Constructor, makes a set by \b moving out of the vector, the vector must be already sorted. MultiIndexSet(size_t cnum_dimensions, std::vector &&new_indexes) : num_dimensions(cnum_dimensions), cache_num_indexes((int)(new_indexes.size() / cnum_dimensions)), indexes(std::move(new_indexes)){} //! \brief Copy a collection of unsorted indexes into a sorted multi-index set, sorts during the copy. MultiIndexSet(Data2D const &data); //! \brief Read from stream constructor. template MultiIndexSet(std::istream &is, iomode) : num_dimensions((size_t) IO::readNumber(is)), cache_num_indexes(IO::readNumber(is)), indexes(IO::readVector(is, Utils::size_mult(num_dimensions, cache_num_indexes))) {} //! \brief Default destructor. ~MultiIndexSet() = default; //! \brief Write the set to ASCII or binary stream, use with std::ofstream and std::ifstream. //! The format consists of two `int` values corresponding to the number of dimensions and number of indexes, //! followed by all the entries of the array on a single line separated by a space, or dump of a single write command. template void write(std::ostream &os) const; //! \brief Returns **true** if there are no multi-indexes in the set, **false** otherwise inline bool empty() const{ return indexes.empty(); } //! \brief Returns the number of dimensions inline size_t getNumDimensions() const{ return num_dimensions; } //! \brief Returns the number of indexes inline int getNumIndexes() const{ return cache_num_indexes; } //! \brief Add more indexes to a non-empty set, \b addition must be sorted and the set must be initialized. void addSortedIndexes(std::vector const &addition); //! \brief If empty, copy \b addition, otherwise merge the indexes of \b addition into this set, i.e., set union. inline MultiIndexSet& operator += (MultiIndexSet const &addition){ num_dimensions = addition.getNumDimensions(); addSortedIndexes(addition.indexes); return *this; } //! \brief Returns a const iterator to the beginning of the internal data inline std::vector::const_iterator begin() const{ return indexes.cbegin(); } //! \brief Returns a const iterator to the end of the internal data inline std::vector::const_iterator end() const{ return indexes.cend(); } //! \brief Returns the number of dimensions times the number of indexes. inline size_t totalSize() const{ return indexes.size(); } //! \brief Moves the index vector out of the class, this method invalidates the object. inline std::vector release(){ return std::move(indexes); } //! \brief Returns the slot containing index **p**, returns `-1` if not found int getSlot(const int *p) const; //! \brief Returns the slot containing index **p**, returns `-1` if not found inline int getSlot(const std::vector &p) const{ return getSlot(p.data()); } //! \brief Returns **true** if **p** is missing from the set, **false** otherwise inline bool missing(const std::vector &p) const{ return (getSlot(p.data()) == -1); } //! \brief Returns the **i**-th index of the set, useful to loop over all indexes or to cross reference with values inline const int *getIndex(int i) const{ return &(indexes[static_cast(i) * num_dimensions]); } //! \brief Returns a copy of the \b i-th index of the set. inline std::vector copyIndex(int i) const{ return std::vector(&indexes[static_cast(i) * num_dimensions], &indexes[static_cast(i) * num_dimensions] + num_dimensions); } /*! \brief Return a new multi-index set that holds the indexed present in this set, but missing in \b substract. * * Assumes that \b substract has the same dimension as this set. * The implementation uses an algorithm similar to merge with complexity linear in the number of multi-indexes of the two sets, * i.e., does not use \b missing() which would add a logarithmic factor. */ MultiIndexSet operator -(const MultiIndexSet &substract) const; //! \brief Removes \b p from the set (if exists). void removeIndex(const std::vector &p); //! \brief Returns the maximum single index in the set. int getMaxIndex() const{ return (empty()) ? 0 : *std::max_element(indexes.begin(), indexes.end()); } private: size_t num_dimensions; int cache_num_indexes; std::vector indexes; }; /*! * \internal * \ingroup TasmanianSets * \brief Class that stores values, i.e., model outputs, the order of the values is in sync with the order of some \b MultiIndexSet * * The StorageSet stores the floating-point values (model outputs) in a contiguous order, suitable for interfacing with BLAS/cuBlas. * The values associated with one model simulation are adjacent to each other in a stride of size \b num_outputs. * Each grid type has one instance of the \b StorageSet and the order of the stored values is kept in sync * with the \b points multi-index set. * Synchronization is achieved by merging values before merging multi-indexes, when * the \b addValues() is called with the old and new multi-index sets and the new values. * \endinternal */ class StorageSet{ public: //! \brief Default constructor, makes an empty set. StorageSet() : num_outputs(0), num_values(0){} //! \brief Move constructor from a known vector. StorageSet(int cnum_outputs, int cnum_values, std::vector &&vals) : num_outputs(cnum_outputs), num_values(cnum_values), values(std::move(vals)){} //! \brief Read constructor. template StorageSet(std::istream &is, iomode) : num_outputs((size_t) IO::readNumber(is)), num_values((size_t) IO::readNumber(is)), values((IO::readFlag(is)) ? IO::readVector(is, Utils::size_mult(num_outputs, num_values)) : std::vector()) {} //! \brief Default destructor. ~StorageSet() = default; /*! * \brief Write the set to ASCII or binary stream, use with std::ofstream and std::ifstream. * * The format consists of two `int` values corresponding to the number of dimensions and number of indexes, * followed by all the entries of the array on a single line separated by a space, or dump of a single write command. */ template void write(std::ostream &os) const; //! \brief Clear the existing values and assigns new dimensions, does not allocate memory for the new values. void resize(int cnum_outputs, int cnum_values){ num_outputs = (size_t) cnum_outputs; num_values = (size_t) cnum_values; values = std::vector(); } //! \brief Returns the number of outputs. size_t getNumOutputs() const{ return num_outputs; } //! \brief Returns const reference to the \b i-th value. double const* getValues(int i) const{ return &(values[i*num_outputs]); } //! \brief Returns reference to the \b i-th value. double* getValues(int i){ return &(values[i*num_outputs]); } //! \brief Replace the existing values with a copy of **vals**, the size must be at least **num_outputs** times **num_values** void setValues(const double vals[]){ values = std::vector(vals, vals + num_outputs * num_values); } //! \brief Replace the existing values with \b vals using move semantics, the size of \b vals must be \b num_outputs times \b num_values void setValues(std::vector &&vals){ num_values = vals.size() / num_outputs; values = std::move(vals); // move assignment } //! \brief Return a StorageSet with values between \b ibegin and \b iend. StorageSet splitValues(int ibegin, int iend) const{ return {iend - ibegin, (int) num_values, spltVector2D(values, num_outputs, ibegin, iend)}; } //! \brief Returns a const iterator to the beginning of the internal data inline std::vector::const_iterator begin() const{ return values.cbegin(); } //! \brief Returns a const iterator to the end of the internal data inline std::vector::const_iterator end() const{ return values.cend(); } //! \brief Moves the values vector out of the class, this method invalidates the object. inline std::vector release(){ return std::move(values); } /*! * \brief Add more values to the set, the \b old_set and \b new_set are the associated multi-index sets required to maintain order. * * Add more values to an existing set of values, where \b old_set and \b new_set indicate the order. * The \b old_set contains the ordered multi-indexes associated with the current values, * the \b new_set corresponds to the order of the \b new_vals. * After the merge, the order of the values will match that of the union of \b old_set and \b new_set. * * Note that the two multi-index sets cannot have repeated entries. */ void addValues(const MultiIndexSet &old_set, const MultiIndexSet &new_set, const double new_vals[]); private: size_t num_outputs, num_values; // kept as size_t to avoid conversions in products, but each one is small individually std::vector values; }; } #endif TASMANIAN-8.1/SparseGrids/tsgLinearSolvers.cpp000066400000000000000000001072471470551176200211600ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_LINEAR_SOLVERS_CPP #define __TASMANIAN_LINEAR_SOLVERS_CPP #include "tsgLinearSolvers.hpp" #include "tsgTPLWrappers.hpp" namespace TasGrid{ void TasmanianDenseSolver::solveLeastSquares(int n, int m, const double A[], double b[], double *x){ // form Ar = A' * A // form x = A' * b std::vector Ar(m * m); #pragma omp parallel for for(int i=0; i=0; i--){ for(int j=i+1; jblasCompatible()){ TasBLAS::solveLS('N', n, m, A, b); std::copy_n(b, m, x); return; }else{ solveLeastSquares(n, m, A, b, x); } } template void TasmanianDenseSolver::solvesLeastSquares(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]){ switch(acceleration->mode){ case accel_gpu_magma: TasGpu::solveLSmultiOOC(acceleration, n, m, A, nrhs, B); break; case accel_gpu_cuda: case accel_gpu_cublas: acceleration->setDevice(); TasGpu::solveLSmulti(acceleration, n, m, A, nrhs, B); break; case accel_cpu_blas: TasBLAS::solveLSmulti(n, m, A, nrhs, B); break; default: throw std::runtime_error("Dense least-squares solve attempted without BLAS or CUDA acceleration enabled."); }; } template void TasmanianDenseSolver::solvesLeastSquaresGPU(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]){ if (not acceleration->on_gpu()) throw std::runtime_error("solvesLeastSquaresGPU() requires a GPU mode to be enabled."); TasGpu::solveLSmultiGPU(acceleration, n, m, A, nrhs, B); } template void TasmanianDenseSolver::solvesLeastSquares(AccelerationContext const*, int, int, double[], int, double[]); template void TasmanianDenseSolver::solvesLeastSquares>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); template void TasmanianDenseSolver::solvesLeastSquaresGPU(AccelerationContext const*, int, int, double[], int, double[]); template void TasmanianDenseSolver::solvesLeastSquaresGPU>(AccelerationContext const*, int, int, std::complex[], int, std::complex[]); namespace Utils{ // implements block transpose method template inline void copy_transpose(long long M, long long N, scalar_type const A[], long long lda, scalar_type B[], long long ldb){ for(int i=0; i void transpose(long long M, long long N, scalar_type const A[], scalar_type B[]){ constexpr long long bsize = 64; long long bM = (M / bsize) + ((M % bsize == 0) ? 0 : 1); // number of blocks in M and N long long bN = (N / bsize) + ((N % bsize == 0) ? 0 : 1); #pragma omp parallel for for(long long t =0; t < bM * bN; t++){ long long i = t / bN; long long j = t % bN; copy_transpose(std::min(bsize, M - i * bsize), std::min(bsize, N - j * bsize), A + i * bsize + j * bsize * M, M, B + i * bsize * N + j * bsize, N); } } template void transpose(long long, long long, float const[], float[]); template void transpose(long long, long long, double const[], double[]); template void transpose(long long, long long, std::complex const[], std::complex[]); } std::vector TasmanianTridiagonalSolver::getSymmetricEigenvalues(int n, std::vector const &diag, std::vector const &offdiag){ #ifndef Tasmanian_ENABLE_BLAS throw std::runtime_error("getSymmetricEigenvalues() requires BLAS acceleration to be enabled!"); #endif std::vector result = diag; std::vector dummy = offdiag; TasBLAS::sterf(n, result.data(), dummy.data()); return result; } void TasmanianTridiagonalSolver::decompose(std::vector &diag, std::vector &off_diag, const double mu0, std::vector &nodes, std::vector &weights) { switch(TasmanianTridiagonalSolver::decompose_version) { case 1 : weights = std::vector(diag.size(), 0.0); weights[0] = sqrt(mu0); nodes = diag; off_diag.push_back(0.0); decompose1(static_cast(diag.size()), nodes, off_diag, weights); break; case 2 : decompose2(diag, off_diag, mu0, nodes, weights); break; default : throw std::invalid_argument("ERROR: decompose_version must be a valid number!"); } } void TasmanianTridiagonalSolver::decompose1(int n, std::vector &d, std::vector &e, std::vector &z){ const double tol = Maths::num_tol; if (n == 1){ z[0] = z[0]*z[0]; return; } for(int l=0; l tol)) m++; while (m != l){ double p = d[l]; double g = (d[l+1] - p) / (2.0 * e[l]); double r = std::sqrt(g*g + 1.0); g = d[m] - p + e[l] / (g + Maths::sign(g) * r); // sign function here may be unstable double s = 1.0; double c = 1.0; p = 0.0; for(int i=m-1; i>=l; i--){ double f = s * e[i]; double b = c * e[i]; if (std::abs(f) >= std::abs(g)){ c = g / f; r = std::sqrt(c*c + 1.0); e[i+1] = f*r; s = 1.0 / r; c *= s; }else{ s = f / g; r = std::sqrt(s*s + 1.0); e[i+1] = g * r; c = 1.0 / r; s *= c; } g = d[i+1] - p; r = (d[i] - g) * s + 2.0 * c * b; p = s * r; d[i+1] = g + p; g = c * r - b; f = z[i+1]; z[i+1] = s * z[i] + c * f; z[i] = c * z[i] - s * f; } d[l] -= p; e[l] = g; e[m] = 0.0; m = l; while((m < n-1) && (std::abs(e[m]) > tol)) m++; } } for(int i=1; i d[j+1]){ double p = d[j]; d[j] = d[j+1]; d[j+1] = p; p = z[j]; z[j] = z[j+1]; z[j+1] = p; } } } for(int i=0; i &diag, std::vector &off_diag, const double mu0, std::vector &nodes, std::vector &weights) { // Ensure compatibility with the ALGOL implementation. // NOTE: diag and off_diag are 1-indexed, while nodes and weights are 0-indexed after this step. size_t n = diag.size(); assert(off_diag.size() == n-1); nodes.resize(n); weights.resize(n); diag.insert(diag.begin(), 0.0); off_diag.insert(off_diag.begin(), 0.0); // SETUP block from ALGOL code. // ALGOL COMMENT: Find the maximum row sum norm and initialize weights. off_diag[0] = 0.0; double norm = 0.0; for (size_t i=1; i<=n-1; i++) { norm = std::max(norm, std::fabs(off_diag[i-1]) + std::fabs(diag[i]) + std::fabs(off_diag[i-1])); weights[i-1] = 0.0; } norm = std::max(norm, std::fabs(diag[n]) + std::fabs(off_diag[n-1])); weights[n-1] = 0.0; weights[0] = 1.0; // Fix the bug in the ALGOL code. double eps = norm * std::numeric_limits::epsilon(); size_t m = n; double lambda{norm}, lambda1{norm}, lambda2{norm}, rho{norm}; // INSPECT block from ALGOL code. // ALGOL COMMENT: Look for convergence of lower diagonal element. while (m > 0) { if (std::fabs(off_diag[m-1]) <= eps) { nodes[m-1] = diag[m]; weights[m-1] = mu0 * weights[m-1] * weights[m-1]; rho = lambda1 < lambda1 ? lambda1 : lambda2; m--; continue; } // ALGOL COMMENT: Small off diagonal element means matrix can be split. size_t k = m-1; while (std::fabs(off_diag[k-1]) > eps) k--; // ALGOL COMMENT: Find eigenvalues of lower 2-by-2 and select accelerating shift. double b2 = off_diag[m-1] * off_diag[m-1]; double det = std::sqrt((diag[m-1] - diag[m]) * (diag[m-1] - diag[m]) + 4.0 * b2); double aa = diag[m-1] + diag[m]; lambda2 = 0.5 * (aa >= 0 ? aa + det : aa - det); lambda1 = (diag[m-1] * diag[m] - b2) / lambda2; double eigmax = std::max(lambda1, lambda2); if (std::fabs(eigmax - rho) <= 0.125 * std::fabs(eigmax)) { lambda = eigmax; } rho = eigmax; // ALGOL COMMENT: Transform block from k to m. double cj = off_diag[k]; off_diag[k-1] = diag[k] - lambda; for (size_t j=k; j<=m-1; j++) { double r = std::sqrt(cj * cj + off_diag[j-1] * off_diag[j-1]); double st = cj / r; double st2 = st * st; double ct = off_diag[j-1] / r; double ct2 = ct * ct; double sc = st * ct; double aj = diag[j]; double bj = off_diag[j]; double wj = weights[j-1]; // Order below is important! diag[j] = aj * ct2 + 2.0 * bj * sc + diag[j+1] * st2; off_diag[j] = (aj - diag[j+1]) * sc + bj * (st2 - ct2); diag[j+1] = aj * st2 - 2.0 * bj * sc + diag[j+1] * ct2; cj = off_diag[j+1] * st; off_diag[j+1] = -off_diag[j+1] * ct; off_diag[j-1] = r; // Account for the offset of the indices. weights[j-1] = wj * ct + weights[j] * st; weights[j] = wj * st - weights[j] * ct; } off_diag[k-1] = 0.0; } // SORT block from ALGOL code. // ALGOL COMMENT: Arrange abscissas in ascending order. // NOTE: the original code used an exchange sort, which is O(n^2). std::vector I(n); for (size_t i=0; i>> &data, std::vector &num_points){ int num_dimensions = (int) num_points.size(); int num_total = 1; for(auto n: num_points) num_total *= n; std::vector cumulative_points(num_dimensions); for(int k=0; k> maps1d(num_total / num_points[k]); // total number of 1-D transforms for(auto &v: maps1d) v.reserve(num_points[k]); // each 1-D transform will have size num_points[k] std::fill(cumulative_points.begin(), cumulative_points.end(), 1); for(int j=num_dimensions-2; j>=0; j--) cumulative_points[j] = cumulative_points[j+1] * ((j+1 != k) ? num_points[j+1] : 1); // convert i to tuple, i.e., i -> p0, p1, p2 .. pd, where d = num_dimensions // all tuples that differ only in the k-th entry will belong to the same 1-D transform // the index of the 1D transform is i1d = \sum_{j \neq k} pj * cumulative_points[j] for(int i=0; i=0; j--){ int pj = t % num_points[j]; // tensor index j if (j != k) i1d += cumulative_points[j] * pj; t /= num_points[j]; } maps1d[i1d].push_back(i); } #pragma omp parallel for // perform the 1D transforms for(int i=0; i<(int) maps1d.size(); i++){ fast_fourier_transform1D(data, maps1d[i]); } } } void TasmanianFourierTransform::fast_fourier_transform1D(std::vector>> &data, std::vector &indexes){ // // Given vector x_n with size N, the Fourier transform F_k is defined as: F_k = \sum_{n=0}^{N-1} \exp(- 2 \pi k n / N) x_n // Assuming that N = 3^l for some l, we can sub-divide the transform into strips of 3 // let j = 0, 1, 2; let k = 0, .., N/3; let x_{0,m} = x_{3m}; let x_{1,m} = x_{3m+1}; and let x_{2,m} = x_{3m+2} // F_{k + j N / 3} = \sum_{m=0}^{N/3 - 1} x_{0,m} \exp(-2 \pi k m / (N / 3)) // + \exp(-2 \pi k / N) \exp(-2 \pi j / 3) \sum_{m=0}^{N/3 - 1} x_{1,m} \exp(-2 \pi k m / (N / 3)) // + \exp(-4 \pi k / N) \exp(-4 \pi j / 3) \sum_{m=0}^{N/3 - 1} x_{2,m} \exp(-2 \pi k m / (N / 3)) // The three sums are the Fourier coefficients of x_{0, m}, x_{1, m}, and x_{2, m} // The terms \exp(-2 \pi k / N) \exp(-2 \pi j / 3), and \exp(-4 \pi k / N) \exp(-4 \pi j / 3) are the twiddle factors // The procedure is recursive splitting the transform into small sets, all the way to size 3 // int num_outputs = (int) data[0].size(); // get the problem dimensions, num outputs and num entries for the 1D transform int num_entries = (int) indexes.size(); // the size of the 1D problem, i.e., N if (num_entries == 1) return; // nothing to do for size 1 // a copy of the data is needed to swap back and forth, thus we make two copies and swap between them std::vector>> V(num_entries); auto v = V.begin(); for(auto i: indexes) *v++ = data[i]; // copy from the data only the indexes needed for the 1D transform std::vector>> W(num_entries); for(auto &w : W) w.resize(num_outputs); // allocate storage for the second data set // the radix-3 FFT algorithm uses two common twiddle factors from known angles +/- 2 pi/3 std::complex twidlep(-0.5, -std::sqrt(3.0) / 2.0); // angle of -2 pi/3 std::complex twidlem(-0.5, std::sqrt(3.0) / 2.0); // angle of 2 pi/3 = -4 pi/3 int stride = num_entries / 3; // the jump between entries, e.g., in one level of split stride is 3, split again and stride is 9 ... up to N / 3 int length = 3; // the number of entries in the sub-sequences, i.e., how large k can be (see above), smallest sub-sequence uses length 3 for(int i=0; i 0){ // when the stride that we just computed is equal to 1, then stop the recursion int biglength = 3 * length; // big sequence, i.e., F_k has this total length int bigstride = stride / 3; double theta = -2.0 * Maths::pi / ((double) biglength); std::complex expstep(std::cos(theta), std::sin(theta)); // initialize the twiddle factors common for this level of sub-sequences std::complex expstep2 = expstep * expstep; // merge sets of 3 sub-sequences (coefficients of x_{i,m}) into 3 pieces of one sequence F_{k + j N / 3} for(int i=0; i t01(1.0, 0.0); std::complex t02(1.0, 0.0); std::complex t11 = twidlep; std::complex t12 = twidlem; std::complex t21 = twidlem; std::complex t22 = twidlep; // the twiddle factors form a 3 by 3 matrix [1, 1, 1; 1, t11, t12; 1, t21, t22;] for(int k=0; k &lpntr, const std::vector> &lindx, const std::vector> &lvals) : tol(Maths::num_tol), num_rows(static_cast(lpntr.size())){ if (num_rows == 0) return; // make an empty matrix // hip doesn't have rocsolver yet, so BLAS is required for dense operations if (acceleration->mode != accel_none and useDense(acceleration, num_rows)){ // dense mode dense = std::vector(Utils::size_mult(num_rows, num_rows)); Utils::Wrapper2D dense_rows(num_rows, dense.data()); auto idx = lindx.begin(); auto vls = lvals.begin(); auto ii = idx->begin(); auto vv = vls->begin(); for(int i=0; iend()){ idx++; vls++; if (idx != lindx.end()){ ii = idx->begin(); vv = vls->begin(); } } double *r = dense_rows.getStrip(i); for(int j=0; jmode != accel_cpu_blas){ // using GPU acceleration->setDevice(); gpu_dense = GpuVector(acceleration, dense); dense = std::vector(); } }else{ // sparse mode pntr = std::vector(num_rows+1, 0); for(int i=0; i(acceleration, num_rows); TasGpu::factorizePLU(acceleration, num_rows, gpu_dense.data(), gpu_ipiv.data()); }else if (not dense.empty()){ ipiv = std::vector(num_rows); TasBLAS::getrf(num_rows, num_rows, dense.data(), num_rows, ipiv.data()); }else{ computeILU(); } } void WaveletBasisMatrix::computeILU(){ indxD.resize(num_rows); ilu.resize(pntr[num_rows]); for(int i=0; i gpu_b(acceleration, num_rows, 1, b); TasGpu::solvePLU(acceleration, 'N', num_rows, gpu_dense.data(), gpu_ipiv.data(), gpu_b.data()); gpu_b.unload(acceleration, b); }else if (not dense.empty()){ TasBLAS::getrs('N', num_rows, 1, dense.data(), num_rows, ipiv.data(), b, num_rows); }else{ // using sparse algorithm if (acceleration->blasCompatible()) solve(std::vector(b, b + num_rows).data(), b); else solve(std::vector(b, b + num_rows).data(), b); } } void WaveletBasisMatrix::invert(AccelerationContext const *acceleration, int num_colums, double B[]){ if (not gpu_dense.empty()){ GpuVector gpu_b(acceleration, num_rows, num_colums, B); if (num_colums == 1){ TasGpu::solvePLU(acceleration, 'T', num_rows, gpu_dense.data(), gpu_ipiv.data(), gpu_b.data()); }else{ TasGpu::solvePLU(acceleration, 'T', num_rows, gpu_dense.data(), gpu_ipiv.data(), num_colums, gpu_b.data()); } gpu_b.unload(acceleration, B); }else if (not dense.empty()){ if (num_colums == 1){ TasBLAS::getrs('T', num_rows, 1, dense.data(), num_rows, ipiv.data(), B, num_rows); }else{ TasBLAS::trsm('R', 'U', 'N', 'N', num_colums, num_rows, 1.0, dense.data(), num_rows, B, num_colums); TasBLAS::trsm('R', 'L', 'N', 'U', num_colums, num_rows, 1.0, dense.data(), num_rows, B, num_colums); // permute Utils::Wrapper2D rows(num_colums, B); for(int i=0; i b(B, B + num_rows); if (acceleration->blasCompatible()) solve(b.data(), B); else solve(b.data(), B); return; } Utils::Wrapper2D wrapb(num_colums, B); std::vector b(num_rows); std::vector x(num_rows); for(int k=0; kblasCompatible()) solve(b.data(), x.data()); else solve(b.data(), x.data()); for(int i=0; i void WaveletBasisMatrix::applyILU(double x[]) const{ if (transpose){ for(int i=0; i=0; i--) for(int j=pntr[i]; j=0; i--){ for(int j=indxD[i]+1; j void WaveletBasisMatrix::apply(double const x[], double r[]) const{ if (transpose){ std::fill_n(r, num_rows, 0.0); for(int i=0; i 0.0) for(int i=0; i 0.0) TasBLAS::scal(num_entries, 1.0 / nrm, x, 1); return nrm; }else{ return rescale(num_entries, x); } } // project the krylov basis inline void projectKrylov(int inner_itr, int max_inner, int num_rows, std::vector &W, std::vector &H){ #pragma omp parallel for for(int i=0; i &W, std::vector &H){ if (AccelerationMeta::isAvailable(accel_cpu_blas)){ TasBLAS::gemv('T', num_rows, inner_itr, 1.0, W.data(), num_rows, &W[inner_itr * num_rows], 1, 0.0, &H[inner_itr-1], max_inner); TasBLAS::gemv('N', num_rows, inner_itr, -1.0, W.data(), num_rows, &H[inner_itr-1], max_inner, 1.0, &W[inner_itr * num_rows], 1); }else{ projectKrylov(inner_itr, max_inner, num_rows, W, H); } } // reconstruct the krylov solution from the basis inline void reconstructKrylov(int inner_itr, int max_inner, int num_rows, std::vector const &W, std::vector const &H, std::vector &Z, double x[]){ Z[inner_itr] /= H[inner_itr * max_inner + inner_itr]; for(int i=inner_itr-1; i>-1; i--){ double beta = 0.0; for(int j=i+1; j<=inner_itr; j++){ beta += H[i*max_inner + j] * Z[j]; }; Z[i] = (Z[i] - beta) / H[i * max_inner + i]; } for(int i=0; i<=inner_itr; i++){ for(int j=0; j const &W, std::vector const &H, std::vector &Z, double x[]){ if (AccelerationMeta::isAvailable(accel_cpu_blas)){ TasBLAS::trsv('L', 'T', 'N', inner_itr, H.data(), max_inner, Z.data(), 1); TasBLAS::gemv('N', num_rows, inner_itr, 1.0, W.data(), num_rows, Z.data(), 1, 1.0, x, 1); }else{ reconstructKrylov(inner_itr, max_inner, num_rows, W, H, Z, x); } } template void WaveletBasisMatrix::solve(const double b[], double x[]) const{ int max_inner = 30; int max_outer = 80; std::vector W((max_inner+1) * num_rows); // Krylov basis std::vector H(max_inner * (max_inner+1)); // holds the transformation for the normalized basis std::vector S(max_inner); // std::sin and std::cos of the Givens rotations std::vector C(max_inner+1); std::vector Z(max_inner); // holds the coefficients of the solution double alpha, beta; // temp variables double outer_res = tol + 1.0; // outer and inner residual int outer_itr = 0; // counts the inner and outer iterations std::vector temp; std::fill_n(x, num_rows, 0.0); // zero initial guess, I wonder if we can improve this while (outer_res > tol and outer_itr < max_outer){ if (transpose){ temp = std::vector(x, x + num_rows); applyILU(temp.data()); apply(temp.data(), W.data()); for(int i=0; i(W.data()); } double inner_res = (blas) ? rescale_blas(num_rows, W.data()) : rescale(num_rows, W.data()); Z[0] = inner_res; int inner_itr = 0; // counts the size of the basis while ((inner_res > tol) && (inner_itr < max_inner-1)){ inner_itr++; if (transpose){ std::copy_n(&(W[num_rows*(inner_itr-1)]), num_rows, temp.data()); applyILU(temp.data()); apply(temp.data(), &W[inner_itr*num_rows]); }else{ apply(&W[num_rows*(inner_itr-1)], &W[inner_itr*num_rows]); applyILU(&W[inner_itr*num_rows]); } if (blas) projectKrylov_blas(inner_itr, max_inner, num_rows, W, H); else projectKrylov(inner_itr, max_inner, num_rows, W, H); beta = (blas) ? rescale_blas(num_rows, &W[inner_itr*num_rows]) : rescale(num_rows, &W[inner_itr*num_rows]); for (int i=0; i -1){ // if the first guess was not within TOL of the true solution if (blas) reconstructKrylov_blas(inner_itr, max_inner, num_rows, W, H, Z, x); else reconstructKrylov(inner_itr, max_inner, num_rows, W, H, Z, x); if (transpose) applyILU(x); } outer_res = inner_res; outer_itr++; } } } /* namespace TasSparse */ } #endif TASMANIAN-8.1/SparseGrids/tsgLinearSolvers.hpp000066400000000000000000000305461470551176200211620ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_LINEAR_SOLVERS_HPP #define __TASMANIAN_LINEAR_SOLVERS_HPP #include "tsgAcceleratedDataStructures.hpp" //! \internal //! \file tsgLinearSolvers.hpp //! \brief Linear solvers. //! \author Miroslav Stoyanov //! \ingroup TasmanianLinearSolvers //! //! Many sparse grids methods rely on various linear solvers, sparse iterative, eigenvalue, //! fast-fourier-transform, and least-squares. The solvers are tuned for the specific //! problems and can perform as good (or even better) than general third-party methods. //! In addition, this reduces the external dependencies. /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianLinearSolvers Linear solvers * * \par Linear Solvers * Many sparse grids methods rely on various linear solvers, sparse iterative, eigenvalue, * fast-fourier-transform, and least-squares. Some solvers use third-party-libraries, * e.g., BLAS and LAPACK, but others are implemented specifically for Tasmanian. * The custom solvers are tuned for the specific problems and can (in the specific circumstances) * outperform than general third-party methods. * Thus, balance is maintained between external dependencies, performance, and capabilities. * \endinternal */ namespace TasGrid{ /*! * \ingroup TasmanianLinearSolvers * \brief Methods for dense linear algebra. * * Most of these build on BLAS and LAPACK, but some come with basic reference implementations. * For example, the general least-squares is used with a single right-hand-size and size of x of 10 - 20, * hence a reference solution is sufficient. */ namespace TasmanianDenseSolver{ /*! * \ingroup TasmanianLinearSolvers * \brief Least squares solver, used to infer anisotropic coefficients and thus rarely exceeds 10 - 20. * * Solves \f$ \min_x \| A x - b \|_2 \f$ where \b A is an \b n by \b m matrix (column major format), * and \b b and \b x are vectors with sizes \b n and \b m. * The assumption here is that \b n is larger than \b m (the problem is over-determined) * and \b A has full column rank. * The use case is for the rates of anisotropic decay which never exceed twice the number of dimensions * and are hence not too large and expensive. */ void solveLeastSquares(int n, int m, const double A[], double b[], double *x); //! \brief The same solver, but uses LAPACK dgels method (if enabled). void solveLeastSquares(AccelerationContext const *acceleration, int n, int m, double A[], double b[], double *x); /*! * \brief Least squares solver, operates on multiple right-hand sides and row-major matrices. * * Solves \f$ \min_x \| A x - B \|_2 \f$ where \b A is an \b n by \b m matrix (row major format), * \b B is \b n by \b nrhs. The main difference in this overload is that the matrices are row-major format. */ template void solvesLeastSquares(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]); //! \brief Overload that accepts arrays on the GPU device. template void solvesLeastSquaresGPU(AccelerationContext const *acceleration, int n, int m, scalar_type A[], int nrhs, scalar_type B[]); } /*! * \ingroup TasmanianLinearSolvers * \brief Methods for tridiagonal eigenvalue problems. */ namespace TasmanianTridiagonalSolver{ //! \brief Method for computing the eigenvalues of a symmetric matrix in place, using an LAPACK wrapper. std::vector getSymmetricEigenvalues(int n, std::vector const &diag, std::vector const &offdiag); //! \brief Specifies the version of decompose to use (for developer use only). static constexpr int decompose_version = 1; //! \brief Method for tridiagonal eigenvalue decomposition, used to compute nodes and weights for Gaussian rules. //! On return, it destroys the inputs \b diag and \b offdiag and writes the outputs to \b nodes and \b weights. The parameter //! mu0 should be set to \f$ \int \mu(x) dx\f$ where \f$ mu(x) dx\f$ is the measure in the function inner product. The //! parameter \b version specifies which algorithm should be called. void decompose(std::vector &diag, std::vector &off_diag, const double mu0, std::vector &nodes, std::vector &weights); //! \brief (decompose_version == 1) TASMANIAN's first internal implementation. void decompose1(int n, std::vector &d, std::vector &e, std::vector &z); //! \brief (decompose_version == 2) Based on the ALGOL code for Golub's 1967 report "Calculation of Gauss Quadrature Rules". void decompose2(std::vector &diag, std::vector &off_diag, const double mu0, std::vector &nodes, std::vector &weights); } //! \internal //! \brief Methods for Fast-Fourier-Transform. //! \ingroup TasmanianLinearSolvers namespace TasmanianFourierTransform{ //! \internal //! \brief Transfrom the data for a multi-dimensional tensor. //! \ingroup TasmanianLinearSolvers //! The \b num_points vector defines the number of points used by the tensor in different directions. //! The \b data holds the values for each point in the tensor, each point has a vector of values //! with size equal to the number of model outputs. //! //! The data is split into one-dimensional \a lines and each is tackled with \b fast_fourier_transform1D() void fast_fourier_transform(std::vector>> &data, std::vector &num_points); //! \internal //! \brief Perform one dimensional fast-fourier-transform (using radix-3). //! \ingroup TasmanianLinearSolvers //! Consider the line which is a subset of \b data defined by \b indexes and perform the radix-3 fast-fourier-transform. //! Called from \b fast_fourier_transform(). void fast_fourier_transform1D(std::vector>> &data, std::vector &indexes); } //! \internal //! \brief Methods for sparse linear algebra. //! \ingroup TasmanianLinearSolvers namespace TasSparse{ //! \internal //! \brief Used to manipulate the wavelet values and solve for the wavelet coefficients. //! \ingroup TasmanianLinearSolvers class WaveletBasisMatrix{ public: //! \brief Default constructor, create an empty matrix. WaveletBasisMatrix() : tol(Maths::num_tol), num_rows(0){} //! \brief Initialize the matrix with the given set of indexes. WaveletBasisMatrix(AccelerationContext const *acceleration, const std::vector &lpntr, const std::vector> &lindx, const std::vector> &lvals); //! \brief Initialize the matrix in dense mode with the given data. WaveletBasisMatrix(AccelerationContext const *acceleration, int cnum_rows, GpuVector &&matrix) : tol(Maths::num_tol), num_rows(cnum_rows), gpu_dense(std::move(matrix)) { factorize(acceleration); } //! \brief Default destructor. ~WaveletBasisMatrix() = default; //! \brief Cannot copy. WaveletBasisMatrix(WaveletBasisMatrix const&) = delete; //! \brief Move constructor. WaveletBasisMatrix(WaveletBasisMatrix &&) = default; //! \brief Cannot copy. WaveletBasisMatrix& operator =(WaveletBasisMatrix const&) = delete; //! \brief Move assignment. WaveletBasisMatrix& operator =(WaveletBasisMatrix &&) = default; //! \brief Decide between sparse and dense variant of the algorithms. static bool useDense(AccelerationContext const *acceleration, int nrows){ return ((acceleration->algorithm_select != AccelerationContext::algorithm_sparse) and not (acceleration->algorithm_select == AccelerationContext::algorithm_autoselect and nrows > 10000)); } //! \brief Return true if using the sparse mode and false is using dense mode or empty. bool isSparse() const{ return (num_rows > 0) and dense.empty(); } //! \brief Return true if using the dense mode and false is using sparse mode or empty. bool isDense() const{ return (num_rows > 0) and not dense.empty(); } //! \brief Return the number of rows in the matrix. int getNumRows() const{ return num_rows; } //! \brief Overwrites vector \b b with \b x that solves \f$ A^T x = b \f$. void invertTransposed(AccelerationContext const *acceleration, double b[]) const; //! \brief Overwrites the row-major matrix \b B with \b X that solves \f$ A X = B \f$. void invert(AccelerationContext const *acceleration, int num_colums, double B[]); //! \brief Solve `op(A) x = b` where `op` is either identity (find the coefficients) or transpose (find the interpolation weights). template void solve(const double b[], double x[]) const; protected: //! \brief Computes the factorization of the matrix, ILU or PLU using the provided acceleration context (called by the constructor). void factorize(AccelerationContext const *acceleration); //! \brief Compute the incomplete lower-upper decomposition of the matrix (zero extra fill). void computeILU(); //! \brief Apply the preconditioner on a vector. template void applyILU(double x[]) const; //! \brief Sets to be the product of the sparse matrix times x. template void apply(double const x[], double r[]) const; //! \brief Computes the residual. void residual(double const x[], double const b[], double r[]) const; //! \brief Expressive call to transpose method. static constexpr bool use_transpose = true; //! \brief Expressive call to no transpose method. static constexpr bool no_transpose = false; //! \brief Expressive call to blas variant method. static constexpr bool use_blas = true; //! \brief Expressive call to no-blas variant method. static constexpr bool no_blas = false; private: double tol; int num_rows; std::vector pntr, indx, indxD; std::vector vals, ilu; std::vector dense; // if using the dense format std::vector ipiv; // pivots for the dense factorize GpuVector gpu_dense; // GPU factors GpuVector gpu_ipiv; }; } } #endif TASMANIAN-8.1/SparseGrids/tsgMathUtils.hpp000066400000000000000000000123101470551176200202710ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_MATHUTILS_HPP #define __TASMANIAN_SPARSE_GRID_MATHUTILS_HPP /*! * \internal * \file tsgMathUtils.hpp * \brief Math functions and constants. * \author Miroslav Stoyanov * \ingroup TasmanianMaths * * Simple functions and constnats used throughout the internal algorithms of Tasmanian. * \endinternal */ /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianMaths Math functions and constants * * \endinternal */ namespace TasGrid{ /*! * \internal * \ingroup TasmanianMaths * \brief Math functions and constants. */ namespace Maths{ /*! * \ingroup TasmanianMaths * \brief Computes std::floor(std::log2(i)), but uses only integer operations. */ inline int intlog2(int i){ int result = 0; while (i >>= 1){ result++; } return result; } /*! * \ingroup TasmanianMaths * \brief Computes std::pow(2, std::floor(std::log2(i))), but uses only integer operations. */ inline int int2log2(int i){ // this is effectively: 2^(floor(log_2(i))), when i == 0, this returns 1 int result = 1; while (i >>= 1){ result <<= 1; } return result; } /*! * \ingroup TasmanianMaths * \brief Computes std::pow(3, std::floor(std::log(i) / std::log(2))), but uses only integer operations. */ inline int int3log3(int i){ int result = 1; while(i >= 1){ i /= 3; result *= 3; } return result; } /*! * \ingroup TasmanianMaths * \brief Computes std::pow(2, p), but uses only integer operations. */ inline int pow2(int p){ return (1 << p); } /*! * \ingroup TasmanianMaths * \brief Computes std::pow(3, p), but uses only integer operations. */ inline int pow3(int p){ int result = 1; for(int i=0; i= 0.0) ? 1.0 : -1.0; } /*! * \internal * \ingroup TasmanianMaths * \brief Half-period of the \b std::sin() and \b std::cos() functions. * * Borrowed from "math.h", let's hope they don't change the value in a future standard. * \endinternal */ constexpr double pi = 3.14159265358979323846; /*! * \internal * \ingroup TasmanianMaths * \brief Numerical tolerance for various algorithms. * * num_tol is used in many places: * - as a stopping criteria for various iterative schemes (e.g., finding leja points) * - drop criteria for eigenvalue solver related to Gauss rules * - comparison between nodes to detect repeated points in non-nested rules (e.g., all odd Chebyshev rules include zero) * - determining sparse matrix pattern, entries smaller than \b num_tol will be ignored (for wavelet grids) * - drop criteria in estimating anisotropic coefficients (refinement or just the coefficients) surpluses or Legendre coefficients below 10^3 times \b num_tol will be ignored * \endinternal */ constexpr double num_tol = 1.E-12; } // namespace Maths } // namespace TasGrid #endif TASMANIAN-8.1/SparseGrids/tsgOneDimensionalWrapper.hpp000066400000000000000000000426131470551176200226350ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_ONE_DIMENSIONAL_WRAPPER_HPP #define __TSG_ONE_DIMENSIONAL_WRAPPER_HPP #include "tsgHardCodedTabulatedRules.hpp" /*! * \internal * \file tsgOneDimensionalWrapper.hpp * \brief Cache for one dimensional rules. * \author Miroslav Stoyanov * \ingroup TasmanianCoreOneDimensional * * A class to cache one dimensional rules, nodes, weight, etc. * \endinternal */ namespace TasGrid{ /*! * \ingroup TasmanianCoreOneDimensional * \brief A class to cache one dimensional rules, nodes, weight, meta-data, etc. */ class OneDimensionalWrapper{ public: //! \brief Default constructor, create an emptry cache. OneDimensionalWrapper() : isNonNested(false), num_levels(0), rule(rule_none){} //! \brief Default destructor. ~OneDimensionalWrapper() = default; /*! * \brief Load the cache. * * Load \b max_level of cache for a rule given by \b crule. If the rule is not * custom tabulated, then \b custom is not used (could be empty). * Similarly, \b alpha and \b beta are used only by rules that use the corresponding * transformation parameters. */ OneDimensionalWrapper(const CustomTabulated &custom, int max_level, TypeOneDRule crule, double alpha, double beta) : isNonNested(OneDimensionalMeta::isNonNested(crule)), num_levels(max_level + 1), rule(crule), num_points(num_levels), pntr(num_levels + 1, 0), // the first entry must be set to zero weights(num_levels), nodes(num_levels), coeff(num_levels) { if (crule == rule_customtabulated){ if (max_level + 1 > custom.getNumLevels()){ std::string message = "ERROR: custom-tabulated rule needed with levels "; message += std::to_string(num_levels); message += ", but only "; message += std::to_string(custom.getNumLevels()); message += " are provided."; throw std::runtime_error(message); } } // find the points per level and the cumulative pointers if (rule != rule_customtabulated){ for(int l=0; l gp.getNumLevels()){ std::string message = "ERROR: gauss-patterson rule needed with level "; message += std::to_string(max_level); message += ", but only "; message += std::to_string(gp.getNumLevels()); message += " are hardcoded."; throw std::runtime_error(message); } unique = gp.getNodes(max_level); // move here to avoid a warning for(int l=0; l(OneDimensionalMeta::getNumPoints(max_level, rule)); }else if ((rule == rule_maxlebesgue) || (rule == rule_maxlebesgueodd)){ unique = Optimizer::getGreedyNodes(OneDimensionalMeta::getNumPoints(max_level, rule)); }else if ((rule == rule_minlebesgue) || (rule == rule_minlebesgueodd)){ unique = Optimizer::getGreedyNodes(OneDimensionalMeta::getNumPoints(max_level, rule)); }else if ((rule == rule_mindelta) || (rule == rule_mindeltaodd)){ unique = Optimizer::getGreedyNodes(OneDimensionalMeta::getNumPoints(max_level, rule)); }else{ // if (rule==rule_fourier) unique = OneDimensionalNodes::getFourierNodes(max_level); } for(int l=0; l lag_x, lag_w; OneDimensionalNodes::getGaussLegendre(n, lag_w, lag_x); for(int l=0; l v(npl); for(int i=0; i=0; j--){ s *= (lag_x[i] - unique[j+1]); v[j] *= s * coeff[l][j]; } for(int j=0; j= num_points[l]) l++; return l; } std::vector getLevels(std::vector const &point){ std::vector result(point.size()); for(size_t i=0; i& getPointsCount() const{ return pntr; } //! \brief Get the loaded rule. TypeOneDRule getRule() const{ return rule; } //! \brief Get the number of cached levels. int getNumLevels() const{ return num_levels; } //! \brief Return reference to all unique nodes. const std::vector& getUnique() const{ return unique; } //! \brief Return all nodes concatenated per level. std::vector getAllNodes() const{ return Utils::mergeVectors(nodes); } //! \brief Return all coefficients concatenated per level. std::vector getAllCoeff() const{ return Utils::mergeVectors(coeff); } //! \brief Return reference to the number of nodes per level. const std::vector& getNumNodesPerLevel() const{ return num_points; } //! \brief Return cumulative points per level. std::vector getOffsetNodesPerLevel() const{ std::vector offsets(num_points.size()); offsets[0] = 0; for(size_t i=1; i num_points; // give the number of points per level std::vector pntr; // gives the cumulative offset of each level std::vector indx; // gives a list of the points associated with each level std::vector> weights; // contains the weight associated with each level std::vector> nodes; // contains all nodes for each level std::vector unique; // contains the x-coordinate of each sample point std::vector> coeff; // the coefficients of the Lagrange }; } #endif TASMANIAN-8.1/SparseGrids/tsgRuleLocalPolynomial.hpp000066400000000000000000001402041470551176200223110ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TSG_RULE_LOCAL_POLYNOMIAL_HPP #define __TSG_RULE_LOCAL_POLYNOMIAL_HPP #include "tsgCoreOneDimensional.hpp" namespace TasGrid{ #ifndef __TASMANIAN_DOXYGEN_SKIP namespace RuleLocal { // effective rule type enum class erule { pwc, localp, semilocalp, localp0, localpb }; inline erule getEffectiveRule(int order, TypeOneDRule rule) { if (order == 0) return erule::pwc; switch(rule) { case rule_semilocalp: return erule::semilocalp; case rule_localp0: return erule::localp0; case rule_localpb: return erule::localpb; default: return erule::localp; } } inline TypeOneDRule getRule(erule effective_rule) { switch(effective_rule) { case erule::pwc: case erule::localp: return rule_localp; case erule::semilocalp: return rule_semilocalp; case erule::localp0: return rule_localp0; default: //case erule::localpb: return rule_localpb; }; } template int getNumPoints(int level) { switch(effective_rule) { case erule::pwc: { int n = 1; while (level-- > 0) n *= 3; return n; } case erule::localp: case erule::semilocalp: return (level == 0) ? 1 : ((1 << level) + 1); case erule::localp0: return (1 << (level+1)) -1; default: // case erule::localpb: return ((1 << level) + 1); }; } template int getMaxNumKids() { return (effective_rule == erule::pwc) ? 4 : 2; } template int getMaxNumParents() { return ((effrule == erule::pwc or effrule == erule::semilocalp or effrule == erule::localpb) ? 2 : 1); } template int getParent(int point) { switch(effective_rule) { case erule::pwc: return (point == 0) ? -1 : point / 3; case erule::localp: case erule::semilocalp: { int dad = (point + 1) / 2; if (point < 4) dad--; return dad; } case erule::localp0: return (point == 0) ? -1 : (point - 1) / 2; default: // case erule::localpb: return (point < 2) ? -1 : ((point + 1) / 2); }; } template int getStepParent(int point) { if (effective_rule == erule::pwc){ int i3l3 = Maths::int3log3(point); if (point == i3l3/3) return -1; if (point == i3l3-1) return -1; int mod3 = point % 3; int mod2 = point % 2; if (mod3 == 2 and mod2 == 0) return point / 3 + 1; if (mod3 == 0 and mod2 == 1) return point / 3 - 1; return -1; }else{ if (effective_rule == erule::semilocalp){ switch(point) { case 3: return 2; case 4: return 1; default: return -1; }; }else if (effective_rule == erule::localpb){ return (point == 2) ? 0 : -1; } return -1; } } template int getKid(int point, int kid_number) { switch(effective_rule) { case erule::pwc: if (point == 0) return (kid_number == 0) ? 1 : (kid_number==1) ? 2 : -1; if (kid_number == 3){ int i3l3 = Maths::int3log3(point); if (point == i3l3/3) return -1; if (point == i3l3-1) return -1; return (point % 2 == 0) ? 3*point + 3 : 3*point - 1; } return 3*point + kid_number; case erule::localp: case erule::semilocalp: if (kid_number == 0){ switch(point) { case 0: return 1; case 1: return 3; case 2: return 4; default: return 2 * point - 1; }; } else { switch(point) { case 0: return 2; case 1: case 2: return -1; default: return 2 * point; }; } case erule::localp0: return 2 * point + ((kid_number == 0) ? 1 : 2); default: // case erule::localpb: switch(point) { case 0: case 1: return (kid_number == 0) ? 2 : -1; default: return 2*point - ((kid_number == 0) ? 1 : 0); }; }; } template double getNode(int point) { switch(effective_rule) { case erule::pwc: return -2.0 + (1.0 / ((double) Maths::int3log3(point))) * (3*point + 2 - point % 2); case erule::localp: case erule::semilocalp: switch(point) { case 0: return 0.0; case 1: return -1.0; case 2: return 1.0; default: return ((double)(2*point - 1)) / ((double) Maths::int2log2(point - 1)) - 3.0; }; case erule::localp0: return ((double)(2*point + 3) ) / ((double) Maths::int2log2(point + 1) ) - 3.0; default: // case erule::localpb: switch(point) { case 0: return -1.0; case 1: return 1.0; case 2: return 0.0; default: return ((double)(2*point - 1)) / ((double) Maths::int2log2(point - 1)) - 3.0; }; }; } template int getLevel(int point) { switch(effective_rule) { case erule::pwc: { int level = 0; while(point >= 1){ point /= 3; level += 1; } return level; } case erule::localp: case erule::semilocalp: return (point == 0) ? 0 : (point == 1) ? 1 : (Maths::intlog2(point - 1) + 1); case erule::localp0: return Maths::intlog2(point + 1); default: // case erule::localpb: return (point <= 1) ? 0 : (Maths::intlog2(point - 1) + 1); }; } template double getSupport(int point) { switch(effective_rule) { case erule::pwc: return 1.0 / (double) Maths::int3log3(point); case erule::localp: case erule::semilocalp: return (point == 0) ? 1.0 : 1.0 / ((double) Maths::int2log2(point - 1)); case erule::localp0: return 1.0 / ((double) Maths::int2log2(point + 1)); default: // case erule::localpb: return (point <= 1) ? 2.0 : 1.0 / ((double) Maths::int2log2(point - 1)); }; } template double scaleDiffX(int point) { switch(effective_rule) { case erule::pwc: return 0.0; case erule::localp: return (point <= 2) ? 1.0 : static_cast(Maths::int2log2(point - 1)); case erule::semilocalp: return static_cast(Maths::int2log2(point - 1)); case erule::localp0: return (point == 0) ? 1.0 : static_cast(Maths::int2log2(point + 1)); default: // case erule::localpb: switch(point) { case 0: case 1: return 0.5; case 2: return 1.0; default: return static_cast(Maths::int2log2(point - 1)); }; }; } template double scaleX(int point, double x) { switch(effective_rule) { case erule::pwc: return 0.0; // should never be called case erule::localp: switch(point) { case 0: return x; case 1: return (x + 1.0); case 2: return (x - 1.0); default: return ((double) Maths::int2log2(point - 1) * (x + 3.0) + 1.0 - (double) (2*point)); }; case erule::semilocalp: return ((double) Maths::int2log2(point - 1) * (x + 3.0) + 1.0 - (double) (2*point)); case erule::localp0: return ((double) Maths::int2log2(point + 1) * (x + 3.0) - 3.0 - (double) (2*point)); default: // case erule::localpb: switch(point) { case 0: return (x + 1.0) / 2.0; case 1: return (x - 1.0) / 2.0; case 2: return x; default: return ((double) Maths::int2log2(point - 1) * (x + 3.0) + 1.0 - (double) (2*point)); }; }; } template double evalPWQuadratic(int point, double x) { if (effective_rule == erule::localp){ switch(point) { case 1: return 1.0 - x; case 2: return 1.0 + x; default: return (1.0 - x) * (1.0 + x); }; }else if (effective_rule == erule::localpb){ switch(point) { case 0: return 1.0 - x; case 1: return 1.0 + x; default: return (1.0 - x) * (1.0 + x); }; } return (1.0 - x) * (1.0 + x); } template double evalPWCubic(int point, double x) { if (effective_rule == erule::localp){ switch(point) { case 0: return 1.0; case 1: return 1.0 - x; case 2: return 1.0 + x; case 3: case 4: return (1.0 - x) * (1.0 + x); default: return (point % 2 == 0) ? (1.0 - x) * (1.0 + x) * (3.0 + x) / 3.0 : (1.0 - x) * (1.0 + x) * (3.0 - x) / 3.0; }; }else if (effective_rule == erule::localp0){ if (point == 0) return (1.0 - x) * (1.0 + x); }else if (effective_rule == erule::localpb){ switch(point) { case 0: return 1.0 - x; case 1: return 1.0 + x; case 2: return (1.0 - x) * (1.0 + x); default: return (point % 2 == 0) ? (1.0 - x) * (1.0 + x) * (3.0 + x) / 3.0 : (1.0 - x) * (1.0 + x) * (3.0 - x) / 3.0; }; } return (point % 2 == 0) ? (1.0 - x) * (1.0 + x) * (3.0 + x) / 3.0 : (1.0 - x) * (1.0 + x) * (3.0 - x) / 3.0; } template double evalPWPower(int max_order, int point, double x) { // use the cubic implementation until we have enough points if (effective_rule == erule::localp) if (point <= 8) return evalPWCubic(point, x); // if order is cubic or less, use the hard-coded functions if (effective_rule == erule::semilocalp) if (point <= 4) return evalPWCubic(point, x); if (effective_rule == erule::localpb) if (point <= 4) return evalPWCubic(point, x); if (effective_rule == erule::localp0) if (point <= 2) return evalPWCubic(point, x); int level = getLevel(point); int most_turns = 1; double value = (1.0 - x)*(1.0 + x); double phantom_distance = 1.0; int max_ancestors = [&]()->int{ // maximum number of ancestors to consider, first set the possible max then constrain by max_order switch(effective_rule) { case erule::pwc: return 0; // should never happen case erule::localp: return max_ancestors = level-2; case erule::semilocalp: return max_ancestors = level-1; case erule::localpb: return max_ancestors = level-1; default: return max_ancestors = level; }; }(); if (max_order > 0) max_ancestors = std::min(max_ancestors, max_order - 2); // use the minimum of the available ancestors or the order restriction for(int j=0; j < max_ancestors; j++){ // Lagrange polynomial needs to be constructed using normalized x (basis support (-1, 1)). // The support of the basis is equal to 2, thus we use units of "half-support" // The first two nodes are used in the initialization of value, those are the nearest ancestors (in spacial distance, not hierarchy level). // The other nodes are "phantoms" that lay strictly outside of the support [-1, 1] (i.e., not on the edge) // The walking distance more than doubles and is an odd number (due to the half-support) // The walk through the ancestors can take a left or right turn at each step, // most_turns is the total number of turns possible for the current ancestor, turns (or most_turns - 1 - turns) is the actual number of turns // Every time we turn, we backtrack and we lose 2 units, the phantom node is at maximum distance minus 2 time the number of turns (to the left or right) most_turns *= 2; phantom_distance = 2.0 * phantom_distance + 1.0; int turns = (effective_rule == erule::localp0) ? ((point+1) % most_turns) : ((point-1) % most_turns); double node = (turns < most_turns / 2) ? (phantom_distance - 2.0 * ((double) turns)) : (-phantom_distance + 2.0 * ((double) (most_turns - 1 - turns))); value *= - ( x - node ) / node; } return value; } template double evalSupport(int max_order, int point, double x, bool &isSupported) { switch(effective_rule) { case erule::pwc: { double distance = std::abs(x - getNode(point)); double support = getSupport(point); isSupported = (distance <= 2.0 * support); return (distance <= support) ? 1.0 : 0.0; } case erule::localp: isSupported = true; if (point == 0) { return 1.0; } else { double xn = scaleX(point, x); if (std::abs(xn) <= 1.0) { switch(max_order) { case 1: return 1.0 - std::abs(xn); case 2: return evalPWQuadratic(point, xn); case 3: return evalPWCubic(point, xn); default: return evalPWPower(max_order, point, xn); }; } else { isSupported = false; return 0.0; } } case erule::semilocalp: isSupported = true; switch(point) { case 0: return 1.0; case 1: return 0.5 * x * (x - 1.0); case 2: return 0.5 * x * (x + 1.0); default: { double xn = scaleX(point, x); if (std::abs(xn) <= 1.0) { switch(max_order) { case 1: return 1.0 - std::abs(xn); case 2: return evalPWQuadratic(point, xn); case 3: return evalPWCubic(point, xn); default: return evalPWPower(max_order, point, xn); }; } else { isSupported = false; return 0.0; } } }; case erule::localp0: default: { // case erule::localpb: double xn = scaleX(point, x); if (std::abs(xn) <= 1.0) { isSupported = true; switch(max_order) { case 1: return 1.0 - std::abs(xn); case 2: return evalPWQuadratic(point, xn); case 3: return evalPWCubic(point, xn); default: return evalPWPower(max_order, point, xn); }; } else { isSupported = false; return 0.0; } } }; } template double evalRaw(int max_order, int point, double x) { switch(effective_rule) { case erule::pwc: return (std::abs(x - getNode(point)) <= getSupport(point)) ? 1.0 : 0.0; case erule::localp: if (point == 0) { return 1.0; } else { double xn = scaleX(point, x); if (std::abs(xn) <= 1.0) { switch(max_order) { case 1: return 1.0 - std::abs(xn); case 2: return evalPWQuadratic(point, xn); case 3: return evalPWCubic(point, xn); default: return evalPWPower(max_order, point, xn); }; } else { return 0.0; } } case erule::semilocalp: switch(point) { case 0: return 1.0; case 1: return 0.5 * x * (x - 1.0); case 2: return 0.5 * x * (x + 1.0); default: { double xn = scaleX(point, x); if (std::abs(xn) <= 1.0) { switch(max_order) { case 1: return 1.0 - std::abs(xn); case 2: return evalPWQuadratic(point, xn); case 3: return evalPWCubic(point, xn); default: return evalPWPower(max_order, point, xn); }; } else { return 0.0; } } }; case erule::localp0: default: { // case erule::localpb: double xn = scaleX(point, x); if (std::abs(xn) <= 1.0) { switch(max_order) { case 1: return 1.0 - std::abs(xn); case 2: return evalPWQuadratic(point, xn); case 3: return evalPWCubic(point, xn); default: return evalPWPower(max_order, point, xn); }; } else { return 0.0; } } }; } template double diffPWQuadratic(int point, double x) { if (effective_rule == erule::localp) { switch(point) { case 1: return -1.0; case 2: return 1.0; default: return -2.0 * x; }; } else if (effective_rule == erule::localpb) { switch(point) { case 0: return -1.0; case 1: return 1.0; default: return -2.0 * x; }; } return -2.0 * x; } template double diffPWCubic(int point, double x) { if (effective_rule == erule::localp) { switch(point) { case 0: return 0.0; case 1: return -1.0; case 2: return 1.0; case 3: case 4: return -2.0 * x; default: return (point % 2 == 0) ? 1.0 / 3.0 - x * (x + 2.0) : -1.0 / 3.0 + x * (x - 2.0); }; } else if (effective_rule == erule::localpb) { switch(point) { case 0: return -1.0; case 1: return 1.0; case 2: return -2.0 * x; default: return (point % 2 == 0) ? 1.0 / 3.0 - x * (x + 2.0) : -1.0 / 3.0 + x * (x - 2.0); }; } else if (effective_rule == erule::localp0) { return (point == 0) ? -2.0 * x : ((point % 2 == 0) ? 1.0 / 3.0 - x * (x + 2.0) : -1.0 / 3.0 + x * (x - 2.0)); } return (point % 2 == 0) ? 1.0 / 3.0 - x * (x + 2.0) : -1.0 / 3.0 + x * (x - 2.0); } template double diffPWPower(int max_order, int point, double x) { // use the cubic implementation until we have enough points if (effrule == erule::localp and point <= 8) return diffPWCubic(point, x); if (effrule == erule::semilocalp and point <= 4) return diffPWCubic(point, x); if (effrule == erule::localpb and point <= 4) return diffPWCubic(point, x); if (effrule == erule::localp0 and point <= 2) return diffPWCubic(point, x); int level = getLevel(point); int max_ancestors = [&]()->int { switch(effrule) { case erule::pwc: return 0; case erule::localp: return level - 2; case erule::semilocalp: case erule::localpb: return level - 1; default: return level; }; }(); if (max_order > 0) max_ancestors = std::min(max_ancestors, max_order - 2); // This lambda captures most_turns and phantom_distance by reference, uses those as internal state variables, and on each // call it returns the next normalized ancestor node. int most_turns = 1; double phantom_distance = 1.0; auto update_and_get_next_node = [&]() { most_turns *= 2; phantom_distance = 2.0 * phantom_distance + 1.0; int turns = (effrule == erule::localp0) ? ((point+1) % most_turns) : ((point-1) % most_turns); return (turns < most_turns / 2) ? (phantom_distance - 2.0 * ((double) turns)) : (-phantom_distance + 2.0 * ((double) (most_turns - 1 - turns))); }; // This lambda is the inverse transform of update_and_get_next_node() above, and returns the previous descendant node. auto rollback_and_get_prev_node = [&]() { most_turns /= 2; phantom_distance = 0.5 * (phantom_distance - 1.0); int turns = (effrule == erule::localp0) ? ((point+1) % most_turns) : ((point-1) % most_turns); return (turns < most_turns / 2) ? (phantom_distance - 2.0 * ((double) turns)) : (-phantom_distance + 2.0 * ((double) (most_turns - 1 - turns))); }; // Does not include the additional factor (1-x) * (1+x) and the Lagrange coefficient. std::vector left_prods(max_ancestors); left_prods[0] = 1.0; double node = update_and_get_next_node(); double coeff = 1.0 / (-node); for(int j=1; j=0; j--) { right_prod *= x - node; derivative += right_prod * left_prods[j]; node = rollback_and_get_prev_node(); } // Adjust for the additional factor (1-x) * (1+x) and the Lagrange coefficient. derivative = derivative * (1.0 - x) * (1.0 + x) + right_prod * (x - node) * (-2.0) * x; derivative *= coeff; return derivative; } template double diffRaw(int max_order, int point, double x) { switch(effrule) { case erule::pwc: return 0.0; case erule::localp: { if (point == 0) return 0.0; double xn = scaleX(point, x); double an = scaleDiffX(point); switch(max_order) { case 1: return ((xn >= 0 ? -1.0 : 1.0) * an); case 2: return an * diffPWQuadratic(point, xn); case 3: return an * diffPWCubic(point, xn); default: return an * diffPWPower(point, xn); }; } case erule::semilocalp: switch(point) { case 0: return 0.0; case 1: return x - 0.5; case 2: return x + 0.5; default: { double xn = scaleX(point, x); double an = scaleDiffX(point); switch(max_order) { case 2: return an * diffPWQuadratic(point, xn); case 3: return an * diffPWCubic(point, xn); default: return an * diffPWPower(point, xn); }; } }; case erule::localp0: { double xn = scaleX(point, x); double an = scaleDiffX(point); switch(max_order) { case 1: return (x == 1.0 and point == 0) ? -1.0 : ((xn >= 0 ? -1.0 : 1.0) * an); case 2: return an * diffPWQuadratic(point, xn); case 3: return an * diffPWCubic(point, xn); default: return an * diffPWPower(point, xn); }; } default: { // case erule::localpb: double xn = scaleX(point, x); double an = scaleDiffX(point); switch(max_order) { case 1: return ((xn >= 0 ? -1.0 : 1.0) * an); case 2: return an * diffPWQuadratic(point, xn); case 3: return an * diffPWCubic(point, xn); default: return an * diffPWPower(point, xn); }; } }; } template double diffSupport(int max_order, int point, double x, bool &isSupported) { switch(effrule) { case erule::pwc: isSupported = false; return 0.0; case erule::localp: { if (point == 0) { isSupported = true; return 0.0; } double xn = scaleX(point, x); isSupported = (-1.0 <= xn and xn < 1.0) or (x == 1.0 and xn == 1.0); if (isSupported) { double an = scaleDiffX(point); switch(max_order) { case 1: return (x == 1.0 and point == 2) ? an : (((xn >= 0 ? -1.0 : 1.0) * an)); case 2: return an * diffPWQuadratic(point, xn); case 3: return an * diffPWCubic(point, xn); default: return an * diffPWPower(max_order, point, xn); }; } else { return 0.0; } } case erule::semilocalp: switch(point) { case 0: { isSupported = true; return 0.0; } case 1: { isSupported = true; return x - 0.5; } case 2: { isSupported = true; return x + 0.5; } default: { double xn = scaleX(point, x); isSupported = (-1.0 <= xn and xn < 1.0) or (x == 1.0 and xn == 1.0); if (isSupported) { double an = scaleDiffX(point); switch(max_order) { case 2: return an * diffPWQuadratic(point, xn); case 3: return an * diffPWCubic(point, xn); default: return an * diffPWPower(max_order, point, xn); }; } else { return 0.0; } } }; case erule::localp0: { double xn = scaleX(point, x); isSupported = (-1.0 <= xn and xn < 1.0) or (x == 1.0 and xn == 1.0); if (isSupported) { double an = scaleDiffX(point); switch(max_order) { case 1: return (x == 1.0 and point == 0) ? -1.0 : ((xn >= 0 ? -1.0 : 1.0) * an); case 2: return an * diffPWQuadratic(point, xn); case 3: return an * diffPWCubic(point, xn); default: return an * diffPWPower(max_order, point, xn); }; } else { return 0.0; } } default: { // case erule::localpb: double xn = scaleX(point, x); isSupported = (-1.0 <= xn and xn < 1.0) or (x == 1.0 and xn == 1.0); if (isSupported) { double an = scaleDiffX(point); switch(max_order) { case 1: return ((xn >= 0 ? -1.0 : 1.0) * an); case 2: return an * diffPWQuadratic(point, xn); case 3: return an * diffPWCubic(point, xn); default: return an * diffPWPower(max_order, point, xn); }; } else { return 0.0; } } }; } template double getArea(int max_order, int point, std::vector const &w, std::vector const &x) { switch(effrule) { case erule::pwc: return 2.0 * getSupport(point); case erule::localp: switch(point) { case 0: return 2.0; case 1: case 2: return 0.5; default: switch(max_order) { case 1: return getSupport(point); case 2: case 3: return (4.0/3.0) * getSupport(point); default: if (point <= 8) return (4.0/3.0) * getSupport(point); break; }; break; }; break; case erule::semilocalp: switch(point) { case 0: return 2.0; case 1: case 2: return 1.0/3.0; default: switch(max_order) { case 2: case 3: return (4.0/3.0) * getSupport(point); default: if (point <= 4) return (4.0/3.0) * getSupport(point); break; }; break; }; break; case erule::localp0: switch(max_order) { case 1: return getSupport(point); case 2: case 3: return (4.0/3.0) * getSupport(point); default: if (point <= 2) return (4.0/3.0) * getSupport(point); break; }; break; default: // case erule::localpb: if (point <= 1) { return 1.0; } else { switch(max_order) { case 1: return getSupport(point); case 2: case 3: return (4.0/3.0) * getSupport(point); default: if (point <= 4) return (4.0/3.0) * getSupport(point); break; }; } break; }; double sum = 0.0; for(size_t i=0; i(max_order, point, x[i]); return sum * getSupport(point); } template void van_matrix(int max_order, int num_rows, std::vector &pntr, std::vector &indx, std::vector &vals) { int max_level = getLevel(num_rows); if (effrule == erule::pwc) { switch(num_rows) { case 0: indx = {0,}; vals = {1.0,}; pntr = {0, 1}; break; case 1: indx = {0, 0, 1}; vals = {1.0, 1.0, 1.0}; pntr = {0, 1, 3}; break; case 2: indx = {0, 0, 1, 0, 2}; vals = {1.0, 1.0, 1.0, 1.0, 1.0}; pntr = {0, 1, 3, 5}; break; default: indx.clear(); indx.reserve(num_rows * max_level); vals.clear(); vals.reserve(num_rows * max_level); pntr = std::vector(num_rows + 1, 0); for(auto i : std::array{0, 0, 1, 0, 2}) indx.push_back(i); for(size_t i=0; i<5; i++) vals.push_back(1.0); pntr[1] = 1; pntr[2] = 3; { std::vector ancestors; ancestors.reserve(max_level); for(int r=3; r(indx.size()); ancestors.clear(); int kid = r; int dad = kid / 3; while(dad != 0) { if (dad % 2 == 0) { if (kid != 3 * dad) ancestors.push_back(dad); } else { if (kid != 3 * dad + 2) ancestors.push_back(dad); } kid = dad; dad = kid / 3; } indx.push_back(0); indx.insert(indx.end(), ancestors.rbegin(), ancestors.rend()); indx.push_back(r); for(size_t i=0; i(indx.size()); } break; }; } else if (effrule == erule::localp) { switch(num_rows) { case 0: indx = {0,}; vals = {1.0,}; pntr = {0, 1}; break; default: indx.clear(); indx.reserve(num_rows * max_level); vals.clear(); vals.reserve(num_rows * max_level); pntr = std::vector(num_rows + 1, 0); indx.push_back(0); vals.push_back(1.0); { std::vector ancestors; std::vector ancestors_vals; ancestors.reserve(max_level); ancestors_vals.reserve(max_level); for(int r=1; r(r); pntr[r] = static_cast(indx.size()); ancestors.clear(); ancestors_vals.clear(); int kid = r; int dad = (kid + 1) / 2; if (kid < 4) dad--; while(dad != 0) { ancestors.push_back(dad); ancestors_vals.push_back( evalRaw(max_order, dad, x) ); kid = dad; dad = (kid + 1) / 2; if (kid < 4) dad--; } indx.push_back(0); indx.insert(indx.end(), ancestors.rbegin(), ancestors.rend()); indx.push_back(r); vals.push_back(1.0); vals.insert(vals.end(), ancestors_vals.rbegin(), ancestors_vals.rend()); vals.push_back(1.0); } pntr.back() = static_cast(indx.size()); } break; }; } else if (effrule == erule::semilocalp) { switch(num_rows) { case 0: indx = {0,}; vals = {1.0,}; pntr = {0, 1}; break; case 1: indx = {0, 0, 1}; vals = {1.0, 1.0, 1.0}; pntr = {0, 1, 3}; break; case 2: indx = {0, 0, 1, 0, 2}; vals = {1.0, 1.0, 1.0, 1.0, 1.0}; pntr = {0, 1, 3, 5}; break; default: indx.clear(); indx.reserve(num_rows * max_level); vals.clear(); vals.reserve(num_rows * max_level); pntr = std::vector(num_rows + 1, 0); for(auto i : std::array{0, 0, 1, 0, 2}) indx.push_back(i); for(int i=0; i<5; i++) vals.push_back(1.0); pntr[1] = 1; pntr[2] = 3; { std::vector ancestors; std::vector ancestors_vals; ancestors.reserve(max_level); ancestors_vals.reserve(max_level); for(int r=3; r(indx.size()); double x = getNode(r); ancestors.clear(); ancestors_vals.clear(); int kid = r; int dad = (kid + 1) / 2; while(dad > 2) { ancestors.push_back(dad); ancestors_vals.push_back( evalRaw(max_order, dad, x) ); kid = dad; dad = (kid + 1) / 2; } indx.push_back(0); indx.push_back(1); indx.push_back(2); indx.insert(indx.end(), ancestors.rbegin(), ancestors.rend()); indx.push_back(r); vals.push_back(1.0); vals.push_back( evalRaw(max_order, 1, x) ); vals.push_back( evalRaw(max_order, 2, x) ); vals.insert(vals.end(), ancestors_vals.rbegin(), ancestors_vals.rend()); vals.push_back(1.0); } pntr.back() = static_cast(indx.size()); } break; }; } else if (effrule == erule::localp0) { switch(num_rows) { case 0: indx = {0,}; vals = {1.0,}; pntr = {0, 1}; break; default: indx.clear(); indx.reserve(num_rows * max_level); vals.clear(); vals.reserve(num_rows * max_level); pntr = std::vector(num_rows + 1, 0); indx.push_back(0); vals.push_back(1.0); { std::vector ancestors; std::vector ancestors_vals; ancestors.reserve(max_level); ancestors_vals.reserve(max_level); for(int r=1; r(r); pntr[r] = static_cast(indx.size()); ancestors.clear(); ancestors_vals.clear(); int kid = r; int dad = (kid - 1) / 2; while(dad != 0) { ancestors.push_back(dad); ancestors_vals.push_back( evalRaw(max_order, dad, x) ); kid = dad; dad = (kid - 1) / 2; } indx.push_back(0); indx.insert(indx.end(), ancestors.rbegin(), ancestors.rend()); indx.push_back(r); vals.push_back( evalRaw(max_order, 0, x) ); vals.insert(vals.end(), ancestors_vals.rbegin(), ancestors_vals.rend()); vals.push_back(1.0); } pntr.back() = static_cast(indx.size()); } break; }; } else { // if (effrule == erule::localpb) { switch(num_rows) { case 0: indx = {0,}; vals = {1.0,}; pntr = {0, 1}; break; case 1: indx = {0, 1}; vals = {1.0, 1.0}; pntr = {0, 1, 2}; break; default: indx.clear(); indx.reserve(num_rows * max_level); vals.clear(); vals.reserve(num_rows * max_level); pntr = std::vector(num_rows + 1, 0); indx.push_back(0); indx.push_back(1); vals.push_back(1.0); vals.push_back(1.0); pntr[1] = 1; { std::vector ancestors; std::vector ancestors_vals; ancestors.reserve(max_level); ancestors_vals.reserve(max_level); for(int r=2; r(indx.size()); double x = getNode(r); ancestors.clear(); ancestors_vals.clear(); int kid = r; int dad = (kid + 1) / 2; while(dad > 1) { ancestors.push_back(dad); ancestors_vals.push_back( evalRaw(max_order, dad, x) ); kid = dad; dad = (kid + 1) / 2; } indx.push_back(0); indx.push_back(1); indx.insert(indx.end(), ancestors.rbegin(), ancestors.rend()); indx.push_back(r); vals.push_back( evalRaw(max_order, 0, x) ); vals.push_back( evalRaw(max_order, 1, x) ); vals.insert(vals.end(), ancestors_vals.rbegin(), ancestors_vals.rend()); vals.push_back(1.0); } pntr.back() = static_cast(indx.size()); } break; }; } } } // namespace RuleLocal #endif // __TASMANIAN_DOXYGEN_SKIP } #endif TASMANIAN-8.1/SparseGrids/tsgRuleWavelet.cpp000066400000000000000000000551611470551176200206240ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "tsgRuleWavelet.hpp" namespace TasGrid{ inline int ACCESS_FINE(int i, int level, int depth){ return ((1 << (depth - level - 1)) * (2 * i + 1)); } inline int ACCESS_COARSE(int i, int level, int depth){ return i * (1 << (depth - level)); } void RuleWavelet::updateOrder(int ord){ // Changes the order of the rule to the specified order. If order other than 1 is // specified, then the approximation to the wavelets will be recalculated. if(order == ord) return; // clear is practically free, call it every time data = std::vector>(); cachexs = std::vector(); order = ord; if(order == 3){ data.resize(5); // (xs, level1 (scaling), level2, level3, level4) data[0].resize(num_data_points); double *xs = data[0].data(); for(int i = 0; i < num_data_points; i++){ xs[i] = -1. + 2*(double (i)) / (double (num_data_points - 1)); } cachexs = std::vector((size_t) 4 * (num_data_points - 3)); for(int i = 0; i < num_data_points - 3; i++){ double const *s = &(xs[i]); double *c = &(cachexs[4*i]); double alpha = 1.0 / ((s[0] - s[3]) * (s[0] - s[2])); double beta = 1.0 / ((s[0] - s[3]) * (s[1] - s[3])); c[0] = alpha / (s[0] - s[1]); c[1] = - alpha / (s[0] - s[1]) - alpha / (s[1] - s[2]) - beta / (s[1] - s[2]); c[2] = alpha / (s[1] - s[2]) + beta / (s[1] - s[2]) + beta / (s[2] - s[3]); c[3] = - beta / (s[2] - s[3]); } // Coefficients derived by solving linear system involving scaling function // integrals and moments. std::vector> coeffs(3); coeffs[0] = {0.95958116146167449, 0.27778015867946454, -0.042754937296610125, -0.014317145809288835, // Second level -0.34358723961941895, 0.36254192315551625, 0.20438681551383264, 0.012027193241660438}; coeffs[1] = {0.90985488901447964, 0.29866296454372104, -0.077377811931657145, 0.017034083534297827, // third level -0.28361250628699103, 0.33723841173046543, 0.24560604387620491, -0.023811935316236606, 0.015786802304611155, 0.23056985382971185, 0.31221657974498912, -0.03868102549989539, 0.194797093133632, -0.099050236091189195, 0.51520570019738199, -0.073403162960780324}; coeffs[2] = {0.90985443399962629, 0.29866318097339162, -0.077377917373678995, 0.017034105626588848, // fourth level -0.28361254472311259, 0.33723844527609648, 0.24560602528531161, -0.023811931411878345, 0.015786801751471, 0.23056986060092344, 0.31221657434994671, -0.038681024059425327, 0.14697942814289319, -0.047340431972365773, 0.51871874565793186, -0.093244980946745618, -0.019628614067688826, 0.25611706552019509, 0.30090457777800012, -0.036629694186987166, -1.0/32.0, 9.0/32.0, 9.0/32.0, -1.0/32.0}; // Initialize scaling functions data[1].resize(3*num_data_points); std::fill(data[1].begin(), data[1].end(), 0.0); // Point (sparse grid numbering): // 1 3 0 4 2 // X --- X --- X --- X --- X // 0 1 2 3 4 // Point (level 2 coarse indexing) // This ordering makes phi1 -> point 0, phi2 -> point 1, phi3 -> point 3 // Points 2 & 4 can be found by reflection of phi2, phi3, respectively. data[1][ACCESS_COARSE(2, 2, iteration_depth)] = 1.0; data[1][num_data_points + ACCESS_COARSE(0, 2, iteration_depth)] = 1.0; data[1][2*num_data_points + ACCESS_COARSE(1, 2, iteration_depth)] = 1.0; cubic_cascade(data[1].data(), 2, iteration_depth); cubic_cascade(&(data[1][num_data_points]), 2, iteration_depth); cubic_cascade(&(data[1][2*num_data_points]), 2, iteration_depth); for(int level = 2; level <= 4; level++){ // Scaling functions at current level. std::vector phi1(num_data_points, 0.0); std::vector phi2(num_data_points, 0.0); std::vector phi3(num_data_points, 0.0); std::vector phi4(num_data_points, 0.0); int num_saved = 2 * (level-1); // 2 'unique' functions at level 2, 4 at 3, 6 at 4. data[level].resize(num_saved * num_data_points); std::fill(data[level].begin(), data[level].end(), 0.0); // Initialize first four scaling functions phi1[ACCESS_COARSE(0, level, iteration_depth)] = 1.0; phi2[ACCESS_COARSE(1, level, iteration_depth)] = 1.0; phi3[ACCESS_COARSE(2, level, iteration_depth)] = 1.0; phi4[ACCESS_COARSE(3, level, iteration_depth)] = 1.0; cubic_cascade(phi1.data(), level, iteration_depth); cubic_cascade(phi2.data(), level, iteration_depth); cubic_cascade(phi3.data(), level, iteration_depth); cubic_cascade(phi4.data(), level, iteration_depth); for(int index = 0; index < num_saved; index++){ // Initialize unlifted wavelet double *wavelet = &data[level][index*(num_data_points)]; wavelet[ACCESS_FINE(index, level, iteration_depth)] = 1; cubic_cascade(wavelet, level, iteration_depth); double c1 = coeffs[level-2][4*index], c2 = coeffs[level-2][4*index+1], c3 = coeffs[level-2][4*index+2], c4 = coeffs[level-2][4*index+3]; if(level > 2 && index >= 2){ // Change pointers around to avoid copying data std::vector tmp; std::swap(tmp, phi1); std::swap(phi1, phi2); std::swap(phi2, phi3); std::swap(phi3, phi4); std::swap(phi4, tmp); // Initialize new scaling function std::fill(phi4.begin(), phi4.end(), 0.0); phi4[ACCESS_COARSE(index+2, level, iteration_depth)] = 1; cubic_cascade(phi4.data(), level, iteration_depth); } for(int i = 0; i < num_data_points; i++){ // Lift the wavelet wavelet[i] -= c1 * phi1[i] + c2 * phi2[i] + c3 * phi3[i] + c4 * phi4[i]; } } } } } void RuleWavelet::cubic_cascade(double *y, int starting_level, int in_iteration_depth){ // Using the cascade algorithm (interpolating subdivision), approximates the values // of the desired scaling function or wavelet at 2^(iteration_depth)+1 points. // Wavelets are generated by placing a 1 in the appropriate place at a fine point // on a given level while scaling functions are generated by placing a 1 in the // appropriate place at a coarse point. for(int level = starting_level; level < in_iteration_depth; level++){ int num_pts = (1 << (level)); int prev_pts = (1 << (level)) + 1; auto AC = [&](int i, int l)->int{ return ACCESS_COARSE(i, l, in_iteration_depth); }; auto AF = [&](int i, int l)->int{ return ACCESS_FINE(i, l, in_iteration_depth); }; // Boundary predictions y[AF(0,level)] += ( 5 *(y[AC(0,level)] + 3*y[AC(1,level)] - y[AC(2,level)]) + y[AC(3,level)] ) / 16.; y[AF(num_pts-1,level)] += ( 5 *(y[AC(prev_pts-1,level)] + 3*y[AC(prev_pts-2,level)] - y[AC(prev_pts-3,level)]) + y[AC(prev_pts-4,level)] ) / 16.; // Central predictions #pragma omp parallel for for(int i = 1; i < num_pts-1; i++){ y[AF(i,level)] += ( 9 * (y[AC(i,level)] + y[AC(i+1,level)]) - (y[AC(i-1,level)] + y[AC(i+2,level)]) ) / 16.; } } } int RuleWavelet::getOrder() const{ return order; } int RuleWavelet::getNumPoints(int level) const{ // Returns the number of points on a given level. if(order == 1){ return (1 << (level + 1)) + 1; }else{ return (1 << (level + 2)) + 1; } } const char * RuleWavelet::getDescription() const{ if (order == 1){ return "First-Order Wavelet Basis"; }else{ return "Third-Order Wavelet Basis"; } } int RuleWavelet::getLevel(int point) const{ // Returns the level to which the given node belongs. if(order == 1){ return (point <= 2) ? 0 : Maths::intlog2(point - 1); }else{ return (point < 5) ? 0 : Maths::intlog2(point - 1) - 1; } } void RuleWavelet::getChildren(int point, int &first, int &second) const{ // Returns the children of the given node in first and second. If the node has only a // single child, then second is set to -1. if (order == 1){ if (point >= 3){ // most likely case first = 2*point-1; second = 2*point; }else if (point < 2 ){ // second most likely case first = 3; second = (point == 0) ? 4 : -1; }else{ // point == 2 first = 4; second = -1; } }else if (order == 3){ if (point >= 3){ first = 2*point-1; second = 2*point; }else if (point == 0){ first = 6; second = 7; }else if (point == 1){ first = 5; second = -1; }else{ // point == 2 first = 8; second = -1; } } } int RuleWavelet::getParent(int point) const{ // Returns the parent of a given node. // Miro: this is a hack, -1 indicates no parent, >= 0 indicates the parent, -2 indicates all nodes on level 0 if (order == 1){ if(point <= 2) return -1; if(point <= 4) return -2; }else{ if(point <= 4) return -1; if(point <= 8) return -2; } return (point+1)/2; } double RuleWavelet::getNode(int point) const { // Returns the x-coordinate in the canonical domain associated with the given wavelet. if (point == 0) return 0.0; if (point == 1) return -1.0; if (point == 2) return 1.0; return ((double)(2*point - 1)) / ((double) Maths::int2log2(point - 1)) - 3.0; } double RuleWavelet::getWeight(int point) const{ // Returns the integral of the given wavelet. if (order == 1){ return (point == 0) ? 1.0 : (point <= 2) ? 0.5 : 0.0; }else if(order == 3){ if (point > 4){ return 0.0; } switch (point){ case 1: case 2: return 1.680555555555555691e-01; case 3: case 4: return 6.611111111111110938e-01; case 0: return 3.416666666666666741e-01; } } return 0.0; } template double RuleWavelet::eval(int point, double x) const{ // Evaluates or differentiates a wavelet designated by point at coordinate x. if(order == 1){ // Level 0 if (point < 3){ double node = getNode(point); if (mode == 0) { double w = 1.0 - std::abs(x - node); return (w < 0.0) ? 0.0 : w; }else{ // Preserve the symmetry of derivatives as much as possible. if (point == 0) return (x < 0.0) ? 1.0 : -1.0; else if (point == 1) return (x < 0.0) ? -1.0 : 0.0; else return (x < 0.0) ? 0.0 : 1.0; } } // Level 1+ return eval_linear(point, x); } else if(order == 3){ return eval_cubic(point, x); } return 0.; } template double RuleWavelet::eval<0>(int point, double x) const; template double RuleWavelet::eval<1>(int point, double x) const; template inline double RuleWavelet::eval_cubic(int point, double x) const{ // Helps stabilize numerical errors. if (point == 0 and x == 0.0 and mode == 1) return 0.0; // Evaluates a third order wavelet at a given point x. double sgn = 1.0; if (point < 5){ // Scaling functions if (point == 2){ // Reflect across y-axis point = 1; sgn = -1.0; x = -x; }else if(point == 4){ point = 3; sgn = -1.0; x = -x; } const double *phi = &(data[1][((point+1)/2) * num_data_points]); return (mode == 0 ? interpolate(phi, x) : sgn * interpolate(phi, x)); } int l = Maths::intlog2(point - 1); if(l == 2){ if (point > 6){ // i.e. 7 or 8 // These wavelets are reflections across the y-axis of 6 & 5, respectively x = -x; sgn = -1.0; point = 13 - point; } point -= 5; const double *phi = &data[2][point*num_data_points]; return (mode == 0 ? interpolate(phi, x) : sgn * interpolate(phi, x)); }else if(l == 3){ if (point > 12){ // i.e. 13, 14, 15, 16 // These wavelets are reflections of 12, 11, 10, 9, respectively x = -x; sgn = -1.0; point = 25 - point; } point -= 9; const double *phi = &data[3][point*num_data_points]; return (mode == 0 ? interpolate(phi, x) : sgn * interpolate(phi, x)); } // Standard lifted wavelets. int subindex = (point - 1) % (1 << l); double scale = pow(2,l-4); double value; if (subindex < 5){ // Left boundary wavelet. value = interpolate(&data[4][subindex*num_data_points], scale * (x + 1.) - 1.); } else if ((1 << l) - 1 - subindex < 5){ // Right boundary wavelet. value = interpolate(&data[4][((1 << l) - subindex - 1)*num_data_points], scale * (1. - x) - 1.); } else { // Central wavelets. double shift = 0.125 * (double (subindex - 5)); value = interpolate(&data[4][5*num_data_points], scale * (x + 1.) -1. - shift); } // Adjust for the chain rule multiplier. if (mode == 1) value *= ((1 << l) - 1 - subindex < 5) ? -scale : scale; return value; } void RuleWavelet::getShiftScale(int point, double &scale, double &shift) const{ if (point < 3){ scale = getNode(point); shift = -1.0; }else{ int l = Maths::intlog2(point - 1); int subindex = (point - 1) % (1 << l); scale = std::pow(2,l-2); if (subindex == 0){ shift = -2.0; }else if (subindex == (1 << l) - 1){ shift = -3.0; }else{ shift = 0.5 * (double (subindex - 1)); } } } double RuleWavelet::getSupport(int point) const{ if (order == 1){ if (point <= 2) return 1.0; // linear-polynomial points return 3.0 / ( 4.0 * std::pow(2.0, Maths::intlog2(point - 1) - 2) ); }else{ if (point <= 8) return 2.0; // cubic-polynomial points and level 1 have global support // the strange 4.2 compensates for numerical errors in computing the cubic-cascade return 4.2 / (3.0 * std::pow(2.0, Maths::intlog2(point - 1) - 3)); } } template inline double RuleWavelet::eval_linear(int point, double x) const{ // Given a wavelet designated by point and a value x, evaluates the wavelet (or its derivative) at x. // If x <= 0 (resp. x > 0), we take only right (resp. left) derivatives. // Standard Lifted Wavelets int l = Maths::intlog2(point - 1); int subindex = (point - 1) % (1 << l); double scale = std::pow(2,l-2); double value; if (subindex == 0){ // Left boundary wavelet. value = linear_boundary_wavelet(scale * (x + 1.) - 1., x <= 0.0); } else if (subindex == (1 << l) - 1) { // Right boundary wavelet. value = linear_boundary_wavelet(scale * (1. - x) - 1., x > 0.0); } else { // Central wavelets double shift = 0.5 * (double (subindex - 1)); value = linear_central_wavelet(scale * (x + 1) - 1. - shift, x <= 0.0); } // Adjust for the chain rule multiplier. if (mode == 1) value *= (subindex == (1 << l) - 1) ? -scale : scale; return value; } template inline double RuleWavelet::linear_boundary_wavelet(double x, bool right) const{ // Evaluates or differentiates the first order boundary wavelet with support on [-1, 0]. // If `right` is true, then we return the right derivatives/values (if they exist); else, we return the left ones. if (std::abs(x + 0.5) > 0.5) return 0.0; if (mode == 0) { if (x < -0.75) { return 0.75 * (7.0 * x + 6.0); } else if ((right and x < -0.5) or (!right and x <= -0.5)) { return -0.25 * (11.0 * x + 6.0); } else if ((right and x < 0) or (!right and x <= 0)) { return 0.25 * x; } else { return 0.0; } } else { if (x < -0.75 or (x == -0.75 and not right)) { return 0.75 * 7.0; } else if (x < -0.5 or (x == -0.5 and not right)) { return -0.25 * 11.0; } else if (x < 0 or (x == 0 and not right)) { return 0.25; } else { // Case: (right and x == 0.0) return 0.0; } } } template inline double RuleWavelet::linear_central_wavelet(double x, bool right) const { // Evaluates or differentiates (right derivative only) the first order central wavelet with support on [-1, .5]. // If `right` is true, then we return the right derivatives/values (if they exist); else, we return the left ones. if (std::abs(x + 0.25) > 0.75) return 0.0; if (mode == 0) { if ( x < -0.5) { return -0.5 * x - 0.5; } else if (x < -0.25) { return 4.0 * x + 1.75;; } else if (x < 0.0) { return -4.0 * x - 0.25; } else if (x < 0.5) { return 0.5 * x - 0.25; } else { return 0.0; } } else { // The ordering is important. if (x < -0.5 or (x == -0.5 and not right)) { return -0.5; } else if (x < -0.25 or (x == -0.25 and not right)) { return 4.0; } else if (x < 0.0 or (x == 0.0 and not right)) { return -4.0; } else if (x < 0.5 or (x == 0.5 and not right)) { return 0.5; } else { // Case: (right and x == 0.5) return 0.0; } } } inline int RuleWavelet::find_index(double x) const{ // Finds an interval such that x_i <= x < x_i+1 using bisection search and returns i. if (x > 1. || x < -1.){ return -1; } // Bisection search const double *xs = data[0].data(); int low = 0; int high = num_data_points-1; while(high - low > 1){ int test = (high + low)/2; if (x < xs[test]){ high = test; } else{ low = test; } } return low; } template inline double RuleWavelet::interpolate(const double *y, double x) const{ // For a given x value and dataset y, calculates the value of the interpolating // polynomial of given order going through the nearby points. constexpr int interpolation_order = 3; int idx = find_index(x); if (idx == -1){ // Outside of table return 0.0; } // Neville's Algorithm if (idx < interpolation_order/2){ idx = interpolation_order/2; }else if(num_data_points - idx - 1 < (interpolation_order+1)/2){ idx = num_data_points - 1 - (interpolation_order+1)/2; } size_t start = (size_t)( idx - interpolation_order / 2 ); double const *xs = &(data[0][start]); double const *ps = &(y[start]); double const dx0 = x - xs[0]; double const dx1 = x - xs[1]; double const dx2 = x - xs[2]; double const dx3 = x - xs[3]; double const *c = &(cachexs[4*start]); if (mode == 0) { return c[0] * ps[0] * dx1 * dx2 * dx3 + c[1] * ps[1] * dx0 * dx2 * dx3 + c[2] * ps[2] * dx0 * dx1 * dx3 + c[3] * ps[3] * dx0 * dx1 * dx2; } else { double dx01 = dx0 * dx1; double dx02 = dx0 * dx2; double dx03 = dx0 * dx3; double dx12 = dx1 * dx2; double dx13 = dx1 * dx3; double dx23 = dx2 * dx3; return c[0] * ps[0] * (dx23 + dx13 + dx12) + c[1] * ps[1] * (dx23 + dx03 + dx02) + c[2] * ps[2] * (dx13 + dx03 + dx01) + c[3] * ps[3] * (dx12 + dx02 + dx01); } } } // namespace TasGrid TASMANIAN-8.1/SparseGrids/tsgRuleWavelet.hpp000066400000000000000000000116051470551176200206240ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_WAVELET_RULE_HPP #define __TASMANIAN_SPARSE_GRID_WAVELET_RULE_HPP #include "tsgGridCore.hpp" namespace TasGrid{ // These macros are used in accessing coarse and fine level coefficients for the cascade algorithm. #ifndef __TASMANIAN_DOXYGEN_SKIP class RuleWavelet{ public: RuleWavelet(int corder, int iter_depth) : order(0), iteration_depth(iter_depth), num_data_points((1 << iteration_depth) + 1){ updateOrder(corder); } ~RuleWavelet() = default; // Interface to Extend int getNumPoints(int level) const; // get the number of points associated with level (also the index of the first point on the level+1) const char* getDescription() const; double getNode(int point) const; // returns the x-value of a point int getOrder() const; void updateOrder(int new_order); // Sets the order of the underlying wavelet rule. Involves recalculating approximations if order==3. double getWeight(int point) const; // get the quadrature weight associated with the point // mode 0: returns the value of point at location x; // mode 1: returns the right derivative (or left derivative if not available) of point at location x; // (there is assumed 1-1 correspondence between points and functions) template double eval(int point, double x) const; int getLevel(int point) const; // returns the hierarchical level of a point void getChildren(int point, int &first, int &second) const; // Given a point, return the children (if any) int getParent(int point) const; // Returns the parent of the given node void getShiftScale(int point, double &scale, double &shift) const; // encodes for GPU purposes double getSupport(int point) const; // return the support of the point, for reporting purposes (not used in eval) protected: template inline double eval_linear(int pt, double x) const; template inline double eval_cubic(int pt, double x) const; template inline double linear_boundary_wavelet(double x, bool right) const; template inline double linear_central_wavelet(double x, bool right) const; int order; int iteration_depth; int num_data_points; static void cubic_cascade(double *y, int starting_level, int iteration_depth); inline int find_index(double x) const; template inline double interpolate(const double y[], double x) const; std::vector> data; std::vector cachexs; }; #endif // __TASMANIAN_DOXYGEN_SKIP } // namespace TasGrid #endif // __TASMANIAN_SPARSE_GRID_WAVELET_RULE_HPP TASMANIAN-8.1/SparseGrids/tsgSequenceOptimizer.cpp000066400000000000000000000550001470551176200220300ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_SEQUENCE_OPTIMIZER_CPP #define __TASMANIAN_SPARSE_GRID_SEQUENCE_OPTIMIZER_CPP #include "tsgSequenceOptimizer.hpp" namespace TasGrid{ namespace Optimizer{ /*! * \ingroup TasmanianSequenceOpt * \brief Computes the coefficients needed for fast evaluation of the Lagrange polynomials. */ std::vector makeCoefficients(std::vector const &nodes){ size_t num_nodes = nodes.size(); std::vector coeffs(num_nodes); for(size_t i=0; i evalLagrange(std::vector const &nodes, std::vector const &coeffs, double x){ int num_nodes = (int) nodes.size(); std::vector lag(nodes.size()); lag[0] = 1.0; for(int i=0; i=0; i--){ w *= (x - nodes[i+1]); lag[i] *= w / coeffs[i]; } return lag; } /*! * \ingroup TasmanianSequenceOpt * \brief Computes the derivative of the \b inode basis functions at \b x. */ double differentiateBasis(std::vector const &nodes, std::vector const &coeffs, size_t inode, double x){ size_t num_nodes = nodes.size(); double s = 1.0; double p = 1.0; double n = (inode != 0) ? (x - nodes[0]) : (x - nodes[1]); for(size_t j=1; j struct CurrentNodes{ //! \brief Default constructor, retain a copy of the nodes and compute the coefficients. CurrentNodes(std::vector const &cnodes) : nodes(cnodes), coeff(makeCoefficients(cnodes)){} //! \brief Constructor that combines the \b cnodes with the \b new_node. CurrentNodes(std::vector const &cnodes, double new_node) : nodes(cnodes){ nodes.push_back(new_node); coeff = makeCoefficients(nodes); } //! \brief Current set of nodes. std::vector nodes; //! \brief Coefficients cache. std::vector coeff; }; /*! * \ingroup TasmanianSequenceOpt * \brief Specialization for \b rule_leja, no need for coefficients. */ template<> struct CurrentNodes{ //! \brief Retain a copy of the nodes. CurrentNodes(std::vector const &cnodes) : nodes(cnodes){} //! \brief Current set of nodes. std::vector nodes; }; /*! * \ingroup TasmanianSequenceOpt * \brief Specialization for \b rule_mindeltaodd, requires two levels. */ template<> struct CurrentNodes{ //! \brief Construct two levels using the \b cnodes and \b cnodes with added \b new_node. CurrentNodes(std::vector const &cnodes, double new_node) : nodes(cnodes), nodes_less1(cnodes), coeff_less1(makeCoefficients(cnodes)){ nodes.push_back(new_node); coeff = makeCoefficients(nodes); } //! \brief Nodes for the current level. std::vector nodes; //! \brief Nodes for the previous level. std::vector nodes_less1; //! \brief Coefficients cache current level. std::vector coeff; //! \brief Coefficients cache for previous level. std::vector coeff_less1; }; /*! * \ingroup TasmanianSequenceOpt * \brief Indicates whether a \b rule has associated derivative, most do. */ template struct HasDerivative{ //! \brief Indicates whether the functional is differentiable. static constexpr bool value = true; }; /*! * \ingroup TasmanianSequenceOpt * \brief Specialization for \b rule_minlebesgue which uses a min-max problem and cannot be differentiated. */ template<> struct HasDerivative{ //! \brief Indicates non-differentiable. static constexpr bool value = false; }; /*! * \ingroup TasmanianSequenceOpt * \brief Specialization for \b rule_mindelta which uses a min-max problem and cannot be differentiated. */ template<> struct HasDerivative{ //! \brief Indicates non-differentiable. static constexpr bool value = false; }; /*! * \ingroup TasmanianSequenceOpt * \brief Computes the value of the functional for given \b x, specialized for each sequence. */ template double getValue(CurrentNodes const&, double){ return 0.0; } /*! * \ingroup TasmanianSequenceOpt * \brief Computes the derivative of the functional for given \b x, specialized for each sequence with \b HasDerivative::value \b = \b true. */ template double getDerivative(CurrentNodes const&, double){ return 0.0; } /*! * \ingroup TasmanianSequenceOpt * \brief Uses the secant method to find local maximum of the functional of the current nodes, uses \b left and \b right as starting points. * * Uses the secant method to find the zero of the derivative of the functional associated with the \b rule. * The method converges fast but may converge to the wrong answer if the initial guess is not close to the zero. * When called from \b computeLocalMaximum(), the result of a coarse pattern search is used as initial guess. */ template OptimizerResult performSecantSearch(CurrentNodes const& current, double left, double right){ auto func = [&](double x)->OptimizerResult{ return {x, getDerivative(current, x)}; }; OptimizerResult past = func(left); OptimizerResult present = func(right); if (std::abs(past.value) < std::abs(present.value)) std::swap(past, present); int iterations = 0; while((std::abs(present.value) > 3.0 * Maths::num_tol) && (iterations < 1000)){ // 1000 guards against stagnation OptimizerResult future = func(present.node - present.value * (present.node - past.node) / (present.value - past.value)); past = present; present = future; iterations++; } return present; } /*! * \ingroup TasmanianSequenceOpt * \brief Finds the maximum of the functional of the current nodes in the interval between \b left_node and \b right_node. * * Uses pattern search with simple left, middle, and right points. * If the functional of the \b rule is differentiable, then the pattern search is used as an initial guess * to secant optimization method. */ template OptimizerResult computeLocalMaximum(CurrentNodes const& current, double left_node, double right_node){ auto func = [&](double x)->OptimizerResult{ return {x, getValue(current, x)}; }; double pattern = 0.5 * (right_node - left_node); // pattern width OptimizerResult left = func(left_node); OptimizerResult middle = func(left_node + pattern); OptimizerResult right = func(right_node); // if differentiable, use coarse tolerance since we will post-process. double tolerance = (HasDerivative::value) ? Maths::num_tol * 1.E-3 : Maths::num_tol; while(pattern > tolerance){ if (middle.value >= std::max(left.value, right.value)){ // middle is largest, shrink pattern /= 2.0; left = func(middle.node - pattern); right = func(middle.node + pattern); }else if (left.value >= std::max(middle.value, right.value)){ // left is the largest if (left.node - pattern < left_node){ // if going out of bounds pattern /= 2.0; right = middle; middle = func(left.node + pattern); }else{ // shift left right = middle; middle = left; left = func(middle.node - pattern); } }else{ // right must be the largest if (right.node + pattern > right_node){ // if going out of bounds pattern /= 2.0; left = middle; middle = func(right.node - pattern); }else{ // shift right left = middle; middle = right; right = func(middle.node + pattern); } } } if (HasDerivative::value){ middle = performSecantSearch(current, left.node, right.node); // this returns the derivative middle = func(middle.node); } return middle; } /*! * \ingroup TasmanianSequenceOpt * \brief Finds the maximum of the functional over the interval (-1, 1). * * Given the \b current set of nodes, construct the functional for the given \b rule * and perform a local optimization on every interval, i.e., compute the local maximum * between every two adjacent nodes in \b current. * The work in done in parallel and the global maximum is reported as the largest among * the local maximums. */ template OptimizerResult computeMaximum(CurrentNodes const& current){ std::vector sorted = current.nodes; std::sort(sorted.begin(), sorted.end()); int num_intervals = (int) sorted.size() - 1; auto func = [&](double x)->OptimizerResult{ return {x, getValue(current, x)}; }; OptimizerResult max_result = func(-1.0); OptimizerResult right_result = func(1.0); if (right_result.value > max_result.value) max_result = right_result; #pragma omp parallel { OptimizerResult thread_max = max_result, thread_result; #pragma omp for schedule(dynamic) for(int i=0; i thread_max.value)) thread_max = thread_result; } #pragma omp critical { if (thread_max.value > max_result.value){ max_result = thread_max; } } } return max_result; } /*! * \ingroup TasmanianSequenceOpt * \brief The \b rule_leja functional. */ template<> double getValue(CurrentNodes const& current, double x){ double p = 1.0; for(auto n : current.nodes) p *= (x - n); return std::abs(p); } /*! * \ingroup TasmanianSequenceOpt * \brief The \b rule_maxlebesgue functional. */ template<> double getValue(CurrentNodes const& current, double x){ std::vector lag = evalLagrange(current.nodes, current.coeff, x); double sum = 0.0; for(auto l : lag) sum += std::abs(l); return sum; } /*! * \ingroup TasmanianSequenceOpt * \brief The \b rule_mindeltaodd functional (indicates companion to \b rule_mindelta for the min-max problem). */ template<> double getValue(CurrentNodes const& current, double x){ auto lag = evalLagrange(current.nodes, current.coeff, x); auto lag_less1 = evalLagrange(current.nodes_less1, current.coeff_less1, x); double result = std::abs(lag.back()); for(size_t i=0; i double getValue(CurrentNodes const& current, double x){ for(auto n : current.nodes) if (std::abs(x - n) < 10 * Maths::num_tol) return -1.E+100; CurrentNodes companion(current.nodes, x); return - computeMaximum(companion).value; } /*! * \ingroup TasmanianSequenceOpt * \brief The \b rule_mindelta functional, uses the \b rule_mindeltaodd functions in min-max problem. */ template<> double getValue(CurrentNodes const& current, double x){ for(auto n : current.nodes) if (std::abs(x - n) < 10 * Maths::num_tol) return -1.E+100; CurrentNodes companion(current.nodes, x); return - computeMaximum(companion).value; } /*! * \ingroup TasmanianSequenceOpt * \brief The derivative of the \b rule_leja functional. */ template<> double getDerivative(CurrentNodes const& current, double x){ double s = 1.0, p = 1.0, n = (x - current.nodes[0]); for(size_t j=1; j double getDerivative(CurrentNodes const& current, double x){ std::vector lag = evalLagrange(current.nodes, current.coeff, x); double sum = 0.0; for(size_t i=0; i double getDerivative(CurrentNodes const& current, double x){ auto lag = evalLagrange(current.nodes, current.coeff, x); auto lag_less1 = evalLagrange(current.nodes_less1, current.coeff_less1, x); double sum = 0.0; for(size_t i=0; i getPrecomputedMinLebesgueNodes(){ return { 0.00000000000000000e+00, 1.00000000000000000e+00, -1.00000000000000000e+00, 5.77350269189625731e-01, -6.82983516382591915e-01, 3.08973641709742008e-01, -8.88438098101029028e-01, 9.01204348257380272e-01, -3.79117423735989223e-01, 7.68752974570125480e-01, -5.49318186832010835e-01, -9.64959809152743819e-01, 9.67682365886019302e-01, -1.28290369854639041e-01, 4.45625686400429988e-01, -8.04184165478832425e-01, 1.67074539986499709e-01, 8.44556006683382599e-01, -4.67815101214832718e-01, -9.88223645152207397e-01, 6.75111201618315282e-01, -2.31781319689011223e-01, 9.90353577025220644e-01, -8.50249643305543756e-01, 3.78518581322005110e-01, -7.34179511891844605e-01, 9.37348529794296281e-01, 7.43693755708555865e-02, -9.43140751144033618e-01, 7.22894448368867515e-01, -3.13966521558236233e-01, 5.21332302672803283e-01, -6.22914216661596742e-01, 9.81207150951301732e-01, -9.96112540596109541e-01, 2.27115897487506796e-01, 8.71343953281246475e-01, -5.83881096023192936e-01, -7.07087869617637754e-02, -9.21222090369298474e-01, 6.35275009690072778e-01, 9.97425667442937813e-01, -7.74028611711955805e-01, 1.19609717340386237e-01, 8.06079215959057738e-01, -9.77828412798477653e-01, -2.81002869364477770e-01, 4.81831205470734381e-01, -4.33236587065744694e-01, 9.51233414543255273e-01}; } std::vector getPrecomputedMinDeltaNodes(){ return { 0.00000000000000000e+00, 1.00000000000000000e+00, -1.00000000000000000e+00, 5.85786437626666157e-01, -7.11391303688287735e-01, -3.65515299787630255e-01, 8.73364116971659943e-01, -9.09934766576546594e-01, 3.48149066530255846e-01, 7.61022503813320816e-01, -5.63728220989981099e-01, 1.61287729090120513e-01, -9.70195195938610255e-01, 9.71760208817352256e-01, -2.12010912937840634e-01, -8.19500788126849566e-01, 9.28317867167342214e-01, 4.63681477197408431e-01, -4.75500758437281013e-01, 6.83991900744136849e-01, -9.89565716162813747e-01, -9.47327399278441035e-02, 9.91020313545615483e-01, -7.70894179555761561e-01, 2.57418053836716398e-01, -9.38159793780884654e-01, 8.23375672488699584e-01, -2.90168112727829441e-01, 5.28028188455664571e-01, -6.43769278853295157e-01, 9.51854409585821237e-01, -8.71963189117939352e-01, 8.85485426816430832e-02, 7.23563624423755547e-01, -9.96440136176172664e-01, -1.50233510276863047e-01, 9.96883045450636107e-01, -5.22343767211049914e-01, 4.02868136231700480e-01, -8.46787710296258989e-01, 8.96281851550158049e-01, -4.11624139689389490e-01, 6.30422054421239331e-01, -9.57396180946457842e-01, 2.09670340519686721e-01, 8.47208170728777743e-01, -6.80096440009749670e-01, -4.07635282203260146e-02, 9.81787150881257009e-01, -9.81715548483999001e-01}; } inline std::vector getPrecomputed(TypeOneDRule rule){ if (rule == rule_leja){ return {0.0, 1.0, -1.0, std::sqrt(1.0/3.0)}; }else if (rule == rule_maxlebesgue){ return {0.0, 1.0, -1.0, 0.5}; }else if (rule == rule_minlebesgue){ return getPrecomputedMinLebesgueNodes(); }else{ // rule_mindelta return getPrecomputedMinDeltaNodes(); } } template double getNextNode(std::vector const &nodes){ return computeMaximum(CurrentNodes(nodes)).node; } template double getNextNode(std::vector const &nodes); template double getNextNode(std::vector const &nodes); template double getNextNode(std::vector const &nodes); template double getNextNode(std::vector const &nodes); template std::vector getGreedyNodes(int n){ // load the first few precomputed nodes auto precomputed = getPrecomputed(rule); size_t usefirst = std::min(precomputed.size(), (size_t) n); std::vector nodes(precomputed.begin(), precomputed.begin() + usefirst); if (n > (int) precomputed.size()){ nodes.reserve((size_t) n); for(int i = (int) precomputed.size(); i(nodes)); } return nodes; } template std::vector getGreedyNodes(int n); template std::vector getGreedyNodes(int n); template std::vector getGreedyNodes(int n); template std::vector getGreedyNodes(int n); } } #endif TASMANIAN-8.1/SparseGrids/tsgSequenceOptimizer.hpp000066400000000000000000000111031470551176200220310ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_SEQUENCE_OPTIMIZER_HPP #define __TASMANIAN_SPARSE_GRID_SEQUENCE_OPTIMIZER_HPP #include "tsgEnumerates.hpp" /*! * \internal * \file tsgSequenceOptimizer.hpp * \brief Algorithms for computing greedy sequences. * \author Miroslav Stoyanov * \ingroup TasmanianSets * * \endinternal */ /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianSequenceOpt Greedy Sequences * * \par Sequence One Dimensional Rules * Nested rules that grow with one point per level allow great flexibility in * constructing sparse grids; however, controlling the Lebesgue constant for * such sequences is a challenge. The standard way to construct a sequence is * to follow a greedy optimization problem, start with a few initial nodes * (usually 0, 1, -1) then add new nodes at the maximum of a specific functional. * Thus, nodes are computed one at a time and one-dimensional optimization * algorithms are needed. * \endinternal */ namespace TasGrid{ namespace Optimizer{ /*! * \ingroup TasmanianSequenceOpt * \brief Simple pair of numbers for the \b node and the \b value of the functional at the node. */ struct OptimizerResult{ //! \brief Node where the functional was evaluated. double node; //! \brief Value of the functional. double value; }; /*! * \ingroup TasmanianSequenceOpt * \brief For the given \b rule and set of \b nodes, compute the next node using the greedy procedure. */ template double getNextNode(std::vector const &nodes); /*! * \ingroup TasmanianSequenceOpt * \brief Get the hard-coded pre-computed nodes. * * Some nodes are very expensive to compute, thus we store a pre-computed set * that contains enough nodes for most applications. */ std::vector getPrecomputedMinLebesgueNodes(); /*! * \ingroup TasmanianSequenceOpt * \brief Get the hard-coded pre-computed nodes. * * Some nodes are very expensive to compute, thus we store a pre-computed set * that contains enough nodes for most applications. */ std::vector getPrecomputedMinDeltaNodes(); /*! * \ingroup TasmanianSequenceOpt * \brief Get \b n nodes for the given sequence \b rule, either compute or use pre-computed. */ template std::vector getGreedyNodes(int n); } } #endif TASMANIAN-8.1/SparseGrids/tsgUtils.hpp000066400000000000000000000144401470551176200174650ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASMANIAN_SPARSE_GRID_UTILS_HPP #define __TASMANIAN_SPARSE_GRID_UTILS_HPP /*! * \internal * \file tsgUtils.hpp * \brief Miscellaneous utility templates used thoughout the code. * \author Miroslav Stoyanov * \ingroup TasmanianUtils * * Templates uses throughout the internal algorithms of Tasmanian. * The header will be kept private. * \endinternal */ #include "tsgMathUtils.hpp" /*! * \internal * \ingroup TasmanianSG * \addtogroup TasmanianUtils Miscellaneous utility templates * * \endinternal */ namespace TasGrid{ /*! * \ingroup TasmanianUtils * \brief Miscellaneous utility templates (internal use). */ namespace Utils{ //! \brief Constructs the transpose of an M by N matrix A in column major format, result is stored in B (implemented in linear solvers). template void transpose(long long M, long long N, scalar_type const A[], scalar_type B[]); //! \brief Constructs the transpose of an M by N matrix A in column major format, result is returned in a vector. template std::vector transpose(long long M, long long N, scalar_type const A[]){ std::vector B(M * N); transpose(M, N, A, B.data()); return B; } /*! * \internal * \brief Converts two integer-like variables to \b size_t and returns the product. * \ingroup TasmanianUtils * \endinternal */ template inline size_t size_mult(IntA a, IntB b){ return static_cast(a) * static_cast(b); } /*! * \internal * \ingroup TasmanianUtils * \brief Copies an array into a vector, returns empty vector if the input is nullpntr. * * \endinternal */ template std::vector::type> copyArray(T* x, I size){ return (x == nullptr) ? std::vector::type>() : std::vector::type>(x, x + static_cast(size)); } /*! * \internal * \ingroup TasmanianUtils * \brief Takes a vector of vectors and returns a single contiguous vector. * * \endinternal */ template std::vector mergeVectors(std::vector> const &vec){ size_t total_size = 0; for(auto const &v : vec) total_size += v.size(); std::vector result; result.reserve(total_size); for(auto const &v : vec) result.insert(result.end(), v.begin(), v.end()); return result; } /*! * \internal * \brief Wraps around a C-style of an array and mimics 2D data-structure. * \ingroup TasmanianUtils * * The Tasmanian external API accepts C-style arrays, which simplifies * interfacing with other languages such as C, Python and Fortran. * The arrays represent 2D data in strips with specific stride, * the Wrapper2D() takes such an array and logically divides it * so strips can be accessed without clumsy double-index notation. * \endinternal */ template class Wrapper2D{ public: //! \brief Wrap around \b raw_data with the given \b stride_size. Wrapper2D(int stride_size, T *raw_data) : stride(static_cast(stride_size)), data(raw_data){} //! \brief Default destructor, \b raw_data has to be deleted elsewhere. ~Wrapper2D(){} //! \brief Return a pointer to the i-th strip. T* getStrip(int i){ return &(data[size_mult(i, stride)]); } private: size_t stride; T *data; }; /*! * \ingroup TasmanianUtils * \brief Equivalent to C++14 enable_if_t */ template using use_if = typename std::enable_if::type; /*! * \ingroup TasmanianUtils * \brief Equivalent to C++14 exchange, but works with simpler types (int, double, float*). */ template T exchange(T& x, U new_x){ T old_x = x; x = static_cast(new_x); return old_x; } /*! * \ingroup TasmanianUtils * \brief Equivalent to C++14 make_unique. */ template std::unique_ptr make_unique(Args&&... args){ return std::unique_ptr(new T(std::forward(args)...)); } } } #endif TASMANIAN-8.1/Tasgrid/000077500000000000000000000000001470551176200143025ustar00rootroot00000000000000TASMANIAN-8.1/Tasgrid/CMakeLists.txt000066400000000000000000000052451470551176200170500ustar00rootroot00000000000000######################################################################## # tasgrid command line tool ######################################################################## ######################################################################## # add the tasgrid executable ######################################################################## add_executable(Tasmanian_tasgrid tasgrid_main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../SparseGrids/gridtestCLICommon.hpp ${CMAKE_CURRENT_SOURCE_DIR}/../SparseGrids/gridtestExternalTests.hpp ${CMAKE_CURRENT_SOURCE_DIR}/../SparseGrids/gridtestExternalTests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../SparseGrids/gridtestTestHelpers.hpp ${CMAKE_CURRENT_SOURCE_DIR}/../SparseGrids/gridtestTestFunctions.hpp ${CMAKE_CURRENT_SOURCE_DIR}/../SparseGrids/gridtestTestFunctions.cpp tasgridWrapper.hpp tasgridWrapper.cpp) target_link_libraries(Tasmanian_tasgrid Tasmanian_addons) set_target_properties(Tasmanian_tasgrid PROPERTIES OUTPUT_NAME "tasgrid" CXX_EXTENSIONS OFF) Tasmanian_rpath_target(TARGET Tasmanian_tasgrid COMPONENTS SparseGrids DREAM) if (Tasmanian_ENABLE_OPENMP) # the OpenMP libraries are carried transitively from sparse grids library target_compile_options(Tasmanian_tasgrid PRIVATE ${OpenMP_CXX_FLAGS}) endif() if (Tasmanian_ENABLE_HIP) target_link_libraries(Tasmanian_tasgrid hip::host) endif() ######################################################################## # Windows specific support (DLL export/import directives and names) ######################################################################## if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") # suppresses warnings regarding pointers to the middle of an array target_compile_definitions(Tasmanian_tasgrid PRIVATE -D_SCL_SECURE_NO_WARNINGS) # needed to prevent crash on using STL vector iterators target_compile_definitions(Tasmanian_tasgrid PUBLIC -D_HAS_ITERATOR_DEBUGGING=0) endif() ######################################################################## # Install binaries and shared objects ######################################################################## install(FILES "${CMAKE_CURRENT_BINARY_DIR}/../configured/tasgridLogs.hpp" DESTINATION include PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) install(TARGETS Tasmanian_tasgrid EXPORT "${Tasmanian_export_name}" RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" ARCHIVE DESTINATION "lib") TASMANIAN-8.1/Tasgrid/tasgridLogs.in.hpp000066400000000000000000000125351470551176200177100ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include #include #define TasmanianGPTableBuild "@CMAKE_CURRENT_BINARY_DIR@/SparseGrids/GaussPattersonRule.table" #define TasmanianGPTableInstall "@Tasmanian_final_install_path@/share/Tasmanian/GaussPattersonRule.table" inline void show_log(){ std::ifstream logfile("@Tasmanian_final_install_path@/share/Tasmanian/Tasmanian.log"); std::cout << "\n" << logfile.rdbuf() << std::endl; } inline void show_cmake_log(){ std::cout << "\nCMake parameters:\n--------------------------------------------------------------------------------" << R"CMAKEVARS( CMAKE_COMMAND @CMAKE_COMMAND@ CMAKE_BUILD_TYPE @CMAKE_BUILD_TYPE@ CMAKE_INSTALL_PREFIX @CMAKE_INSTALL_PREFIX@ CMAKE_CXX_FLAGS @CMAKE_CXX_FLAGS@ CMAKE_CXX_FLAGS_DEBUG @CMAKE_CXX_FLAGS_DEBUG@ CMAKE_CXX_FLAGS_RELEASE @CMAKE_CXX_FLAGS_RELEASE@ CMAKE_CXX_COMPILER @CMAKE_CXX_COMPILER@ CMAKE_CUDA_COMPILER @CMAKE_CUDA_COMPILER@ CMAKE_CUDA_ARCHITECTURES @CMAKE_CUDA_ARCHITECTURES@ CMAKE_CUDA_FLAGS @CMAKE_CUDA_FLAGS@ CMAKE_CUDA_FLAGS_DEBUG @CMAKE_CUDA_FLAGS_DEBUG@ CMAKE_CUDA_FLAGS_RELEASE @CMAKE_CUDA_FLAGS_RELEASE@ Tasmanian_cudamathlibs @Tasmanian_cudamathlibs@ Tasmanian_cudaruntime @Tasmanian_cudaruntime@ Python_EXECUTABLE @Python_EXECUTABLE@ BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@ BLAS_LIBRARIES @BLAS_LIBRARIES@ LAPACK_LIBRARIES @LAPACK_LIBRARIES@ CMAKE_THREAD_LIBS_INIT @CMAKE_THREAD_LIBS_INIT@ OpenMP_CXX_LIBRARIES @OpenMP_CXX_LIBRARIES@ OpenMP_CXX_FLAGS @OpenMP_CXX_FLAGS@ MPI_CXX_LIBRARIES @MPI_CXX_LIBRARIES@ MPI_CXX_INCLUDE_PATH @MPI_CXX_INCLUDE_PATH@ MPI_CXX_COMPILE_FLAGS @MPI_CXX_COMPILE_FLAGS@ MPI_CXX_LINK_FLAGS @MPI_CXX_LINK_FLAGS@ MPIEXEC_EXECUTABLE @MPIEXEC_EXECUTABLE@ Tasmanian_ENABLE_RECOMMENDED @Tasmanian_ENABLE_RECOMMENDED@ Tasmanian_ENABLE_OPENMP @Tasmanian_ENABLE_OPENMP@ Tasmanian_ENABLE_BLAS @Tasmanian_ENABLE_BLAS@ Tasmanian_ENABLE_PYTHON @Tasmanian_ENABLE_PYTHON@ Tasmanian_ENABLE_CUDA @Tasmanian_ENABLE_CUDA@ Tasmanian_ENABLE_HIP @Tasmanian_ENABLE_HIP@ Tasmanian_ENABLE_DPCPP @Tasmanian_ENABLE_DPCPP@ Tasmanian_ENABLE_FORTRAN @Tasmanian_ENABLE_FORTRAN@ Tasmanian_ENABLE_MPI @Tasmanian_ENABLE_MPI@ Tasmanian_ENABLE_MAGMA @Tasmanian_ENABLE_MAGMA@ Tasmanian_MATLAB_WORK_FOLDER @Tasmanian_MATLAB_WORK_FOLDER@ Tasmanian_ENABLE_DOXYGEN @Tasmanian_ENABLE_DOXYGEN@ DOXYGEN_INTERNAL_DOCS @DOXYGEN_INTERNAL_DOCS@ Tasmanian_PYTHONPATH @Tasmanian_PYTHONPATH@ Tasmanian_final_install_path @Tasmanian_final_install_path@)CMAKEVARS" << "\n--------------------------------------------------------------------------------\n" << std::endl; } TASMANIAN-8.1/Tasgrid/tasgridWrapper.cpp000066400000000000000000001302101470551176200200010ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #ifndef __TASGRID_WRAPPER_CPP #define __TASGRID_WRAPPER_CPP #include "tsgExoticQuadrature.hpp" #include "tasgridWrapper.hpp" template using CArr = std::array; // helper class struct internal_sparse_matrix{ int num_cols; std::vector pntr, indx; std::vector vals; internal_sparse_matrix(int cols) : num_cols(cols){} template void writeSparseMatrix(std::ostream &os) const{ int nnz = static_cast(indx.size()); int rows = static_cast(pntr.size() - 1); IO::writeNumbers(os, rows, num_cols, nnz); IO::writeVector(pntr, os); IO::writeVector(indx, os); IO::writeVector(vals, os); } void write(std::string const &filename, bool use_ascii) const{ if (not filename.empty()){ if (use_ascii){ std::ofstream ofs(filename); ofs << std::scientific; ofs.precision(17); writeSparseMatrix(ofs); }else{ std::ofstream ofs(filename, std::ios::out | std::ios::binary); char charTSG[3] = {'T', 'S', 'G'}; ofs.write(charTSG, 3 * sizeof(char)); writeSparseMatrix(ofs); } } } void write(bool print_to_cout) const{ if (print_to_cout){ cout << std::scientific; cout.precision(17); writeSparseMatrix(cout); } } }; TasgridWrapper::TasgridWrapper() : command(command_none), num_dimensions(0), num_outputs(-1), depth(-1), order(1), depth_type(type_none), rule(rule_none), conformal(conformal_none), alpha(0.0), beta(0.0), set_alpha(false), set_beta(false), tolerance(0.0), set_tolerance(false), ref_output(-1), min_growth(-1), tref(refine_fds), set_tref(false), printCout(false), useASCII(false), set_gpuid(-2), shift(0.0), set_shift(false) {} TasgridWrapper::~TasgridWrapper(){} TypeCommand TasgridWrapper::hasCommand(std::string const &s){ std::map commands = { {"-makeglobal", command_makeglobal}, {"-mg", command_makeglobal}, {"-makesequence", command_makesequence}, {"-ms", command_makesequence}, {"-makelocalpoly", command_makelocalp}, {"-mp", command_makelocalp}, {"-makewavelet", command_makewavelet}, {"-mw", command_makewavelet}, {"-makefourier", command_makefourier}, {"-mf", command_makefourier}, {"-makequadrature", command_makequadrature}, {"-mq", command_makequadrature}, {"-makeexoquad", command_makeexoquad}, {"-meq", command_makeexoquad}, {"-makeupdate", command_update}, {"-mu", command_update}, {"-setconformal", command_setconformal}, {"-sc", command_setconformal}, {"-getquadrature", command_getquadrature}, {"-gq", command_getquadrature}, {"-getinterweights", command_getinterweights}, {"-gi", command_getinterweights}, {"-getdiffweights", command_getdiffweights}, {"-gd", command_getdiffweights}, {"-getpoints", command_getpoints}, {"-gp", command_getpoints}, {"-getneeded", command_getneeded}, {"-gn", command_getneeded}, {"-loadvalues", command_loadvalues}, {"-l", command_loadvalues}, {"-evaluate", command_evaluate}, {"-e", command_evaluate}, {"-integrate", command_integrate}, {"-i", command_integrate}, {"-differentiate", command_differentiate}, {"-d", command_differentiate}, {"-evalhierarchyd", command_evalhierarchical_dense}, {"-ehd", command_evalhierarchical_dense}, {"-evalhierarchys", command_evalhierarchical_sparse}, {"-ehs", command_evalhierarchical_sparse}, {"-gethsupport", command_gethsupport}, {"-ghsup", command_gethsupport}, {"-getanisotropy", command_getanisocoeff}, {"-ga", command_getanisocoeff}, {"-refinesurp", command_refine_surp}, {"-rs", command_refine_surp}, {"-refineaniso", command_refine_aniso}, {"-ra", command_refine_aniso}, {"-refine", command_refine}, {"-r", command_refine}, {"-cancelrefine", command_refine_clear}, {"-cr", command_refine_clear}, {"-mergerefine", command_refine_merge}, {"-mr", command_refine_merge}, {"-using-construct", command_using_construct}, {"-getconstructpnts", command_get_candidate_construction}, {"-gcp", command_get_candidate_construction}, {"-loadconstructed", command_load_construction}, {"-lcp", command_load_construction}, {"-summary", command_summary}, {"-s", command_summary}, {"-getcoefficients", command_getcoefficients}, {"-gc", command_getcoefficients}, {"-setcoefficients", command_setcoefficients}, {"-sc", command_setcoefficients}, {"-getpoly", command_getpoly}, {"-getpointsindexes", command_getpointsindex}, {"-getneededindexes", command_getneededindex} }; try{ return commands.at(s); }catch(std::out_of_range &){ return command_none; } } TypeConformalMap TasgridWrapper::getConfromalType(const char* name){ if (std::string(name) == "asin"){ return conformal_asin; }else{ return conformal_none; } } bool TasgridWrapper::isCreateCommand(TypeCommand com){ return ( (com == command_makeglobal) || (com == command_makesequence) || (com == command_makelocalp) || (com == command_makewavelet) || (com == command_makefourier) || (com == command_makequadrature) || (com == command_makeexoquad)); } struct command_tester{ TypeCommand command; template> bool inside(std::array const &command_list1, vec2_t const &command_list2 = {}){ return (std::any_of(command_list1.begin(), command_list1.end(), [&](TypeCommand c)->bool{ return (c == command); }) or std::any_of(command_list2.begin(), command_list2.end(), [&](TypeCommand c)->bool{ return (c == command); })); } }; struct test_result_wrapper{ bool pass = true; operator bool() const{ return pass; } void fail_if(bool condition, const char *text){ if (condition){ cerr << "ERROR: " << text << "\n"; pass = false; } } void worry_if(bool condition, const char *text){ if (condition) cerr << "WARNING: " << text << "\n"; } }; bool TasgridWrapper::checkSane() const{ if (command == command_none){ cerr << "ERROR: no command specified\n"; return false; } command_tester com{command}; CArr<5> makecoms = {command_makeglobal, command_makesequence, command_makelocalp, command_makewavelet, command_makefourier}; test_result_wrapper test; // adopt the signature for the checks, problem and commands that have the problem // e.g., num_dimensions < 1 is problem when using make-grid command or make quadrature test.fail_if(num_dimensions < 1 and com.inside(makecoms, CArr<1>{command_makequadrature}), "must specify number of dimensions (e.g., number of model inputs)"); test.fail_if(num_outputs < 1 and com.inside(makecoms), "must specify number of outputs (could be zero)"); test.fail_if(depth < 0 and com.inside(makecoms, CArr<3>{command_makequadrature, command_makeexoquad, command_update}), "must specify depth (e.g., level or polynomial degree)"); test.fail_if(order < -1 and (command == command_makelocalp or (command == command_makequadrature and OneDimensionalMeta::isLocalPolynomial(rule))), "the maximum order for local polynomial cannot be less than -1"); test.fail_if(order != 1 and order != 3 and (command == command_makewavelet or (command == command_makequadrature and OneDimensionalMeta::isWavelet(rule))), "the wavelet order must be either 1 or 3"); test.fail_if(depth_type == type_none and (com.inside(CArr<6>{command_makeglobal, command_makesequence, command_makefourier, command_update, command_getanisocoeff, command_getpoly}) or (command == command_makequadrature and (OneDimensionalMeta::isGlobal(rule) or OneDimensionalMeta::isFourier(rule)))), "must specify depth_type (e.g., select levels or polynomial basis)"); test.fail_if(rule == rule_none and com.inside(CArr<4>{command_makeglobal, command_makesequence, command_makelocalp, command_makequadrature}), "must specify rule to use (e.g., clenshaw-curtis or localp)"); if (command == command_makeglobal or command == command_makequadrature){ bool needs_alpha = (rule == rule_gaussgegenbauer or rule == rule_gausslaguerre or rule == rule_gausshermite or rule == rule_gaussgegenbauerodd or rule == rule_gausshermiteodd or rule == rule_gaussjacobi); bool needs_beta = (rule == rule_gaussjacobi); test.fail_if(not set_alpha and needs_alpha, (std::string("one dimensional rule ") + IO::getRuleString(rule) + " requires alpha parameter").c_str()); test.fail_if(not set_beta and needs_beta, (std::string("one dimensional rule ") + IO::getRuleString(rule) + " requires alpha parameter").c_str()); test.worry_if(set_alpha and not needs_alpha, (std::string("alpha parameter set, but one dimensional rule ") + IO::getRuleString(rule) + " doesn't depend on alpha").c_str()); test.worry_if(set_beta and not needs_beta, (std::string("beta parameter set, but one dimensional rule ") + IO::getRuleString(rule) + " doesn't depend on beta").c_str()); test.fail_if(customfilename.empty() and rule == rule_customtabulated, "ustom-tabulated rule specified, but no -customflile given"); test.worry_if(not customfilename.empty() and rule != rule_customtabulated, "custom-tabulated rule specified, but no -customflile given"); } // not output at all test.fail_if(gridfilename.empty() and outfilename.empty() and not printCout and com.inside(makecoms), "no means of output are specified, you should specify -gridfile, -outfile or -print"); // cannot output to gridfile and outfile and print are not set test.fail_if(outfilename.empty() and not printCout and com.inside(CArr<16>{command_makequadrature, command_makeexoquad, command_getinterweights, command_evaluate, command_evalhierarchical_dense, command_evalhierarchical_sparse, command_differentiate, command_get_candidate_construction, command_getquadrature, command_getpoints, command_getneeded, command_getcoefficients, command_gethsupport, command_integrate, command_getanisocoeff, command_getpoly}), "no means of output are specified, you should specify -outfile or -print"); test.fail_if(conformalfilename.empty() and conformal != conformal_none, "conformal transform requires both -conformaltype and -conformalfile"); test.fail_if(conformal == conformal_none and command == command_setconformal, "must specify valid -conformaltype"); test.fail_if(conformalfilename.empty() and command == command_setconformal, "must specify valid -conformalfile"); test.fail_if(gridfilename.empty() and not com.inside(makecoms, CArr<2>{command_makequadrature, command_makeexoquad}), "must specify valid -gridfile"); test.fail_if(xfilename.empty() and com.inside(CArr<6>{command_getinterweights, command_evaluate, command_evalhierarchical_dense, command_evalhierarchical_sparse, command_differentiate, command_load_construction}), "must specify valid -pointsfile"); test.fail_if(valsfilename.empty() and com.inside(CArr<3>{command_loadvalues, command_setcoefficients, command_load_construction}), "must specify valid -valsfile"); // handle special cases per command switch(command){ case command_makeglobal: test.fail_if(not OneDimensionalMeta::isGlobal(rule), (std::string("cannot use global grids with rule: ") + IO::getRuleString(rule)).c_str()); break; case command_makesequence: test.fail_if(not OneDimensionalMeta::isSequence(rule), (std::string("rule is set to ") + IO::getRuleString(rule) + " which is not a sequence rule (e.g., leja, rleja, min/max-lebesgue)").c_str()); break; case command_makelocalp: test.fail_if(not OneDimensionalMeta::isLocalPolynomial(rule), (std::string("cannot use local polynomial grids with rule: ") + IO::getRuleString(rule)).c_str()); break; case command_makeexoquad: test.fail_if(not set_shift, "must specify shift parameter"); test.fail_if(weightfilename.empty(), "must specify shift parameter"); test.fail_if(description.empty(), "must specify description string"); break; case command_getpoly: test.fail_if(depth_type == type_level or depth_type == type_curved or depth_type == type_hyperbolic, "the type here must start with either i or q indicating whether we seek the polynomils for integration or interpolation"); break; default: break; } test.worry_if(num_outputs != -1 and command == command_makequadrature, "ignoring the -outputs specified for the -makequadrature command"); test.worry_if(not gridfilename.empty() and command == command_makequadrature, "quadrature does not output a -gridfile, if you need a gridfile use -makeglobal/-makelocalpoly commands followed by -getquadrature"); test.worry_if(not conformalfilename.empty() and conformal == conformal_none, "conformal transform requires both -conformaltype and -conformalfile, ignoring conformal mapping"); return test; } bool TasgridWrapper::checkSanePostRead() const{ command_tester com{command}; test_result_wrapper test; test.fail_if(grid.getNumLoaded() == 0 and com.inside(CArr<8>{command_evaluate, command_differentiate, command_integrate, command_getanisocoeff, command_getcoefficients, command_refine, command_refine_aniso, command_refine_surp}), "the grid has no loaded data"); test.fail_if(grid.getNumOutputs() == 0 and com.inside(CArr<9>{command_evaluate, command_differentiate, command_integrate, command_getanisocoeff, command_getcoefficients, command_refine, command_refine_aniso, command_refine_surp, command_get_candidate_construction}), "the grid has no outputs"); test.fail_if(ref_output >= grid.getNumOutputs() and com.inside(CArr<1>{command_getanisocoeff, }), "-refout outside of the range, note the outputs are indexed from zero"); test.fail_if(ref_output == -1 and grid.getNumOutputs() > 1 and grid.isGlobal() and com.inside(CArr<1>{command_getanisocoeff}), "-refout cannot use -1 when working with Global grids"); test.fail_if((grid.isLocalPolynomial() or grid.isWavelet()) and command == command_refine_aniso, "anisotropic operations are available only for Global, Sequence and Fourier grids"); test.fail_if((grid.isFourier() and command == command_refine_surp), "surplus refinement cannot be applied to Fourier grids"); bool is_refine = (command == command_refine or command == command_get_candidate_construction); if (command == command_refine_aniso or (is_refine and (grid.isGlobal() or grid.isSequence() or grid.isFourier()))){ test.fail_if(grid.isLocalPolynomial() or grid.isWavelet(), "anisotropic refinement can be applied only to Global, Sequence and Fourier grids"); test.fail_if(depth_type == type_none, "anisotropic refinement requires depth type with -tt"); test.fail_if(ref_output == -1 and grid.getNumOutputs() > 1 and grid.isGlobal() and com.inside(CArr<1>{command_getanisocoeff}), "-refout cannot use -1 when working with Global grids"); test.worry_if(set_tolerance, "anisotropic refinement (and grids Global, Sequence, Fourier) ignores the -tolerance option"); test.worry_if(set_tref, "anisotropic refinement (and grids Global, Sequence, Fourier) ignores the -reftype option"); } if (command == command_refine_surp or (is_refine and (grid.isLocalPolynomial() or grid.isWavelet()))){ test.fail_if(not set_tolerance, "must specify -tolerance for surplus refinement"); test.fail_if(not set_tref, "must specify -reftype option"); test.worry_if(not valsfilename.empty() and (grid.isGlobal() or grid.isSequence() or grid.isFourier()), "the scale factors are not used with Global, Sequence and Fourier grids"); } test.fail_if((grid.isLocalPolynomial() or grid.isWavelet()) and command == command_getpoly, "cannot call -getpoly for a grid that is neither Global nor Sequence"); return test; } void TasgridWrapper::iassert(bool condition, const char* text) const{ if (not condition){ cerr << "ERROR: " << text << "\n"; pass_flag = false; } } bool TasgridWrapper::executeCommand(){ if (not checkSane()) return false; pass_flag = true; if (command == command_makeexoquad){ createExoticQuadrature(); return pass_flag; } if (set_gpuid > -2){ try{ grid.enableAcceleration(accel_gpu_cuda, set_gpuid); }catch(std::runtime_error &e){ cerr << "WARNING: setting the GPU failed with the following message: \n"; cerr << e.what() << "\n"; } } command_tester com{command}; CArr<6> makecoms = {command_makeglobal, command_makesequence, command_makelocalp, command_makewavelet, command_makefourier, command_makequadrature}; CArr<2> quadcoms = {command_makequadrature, command_getquadrature}; CArr<17> constcoms = { command_getquadrature, command_getinterweights, command_getdiffweights, command_getpoints, command_getneeded, command_evaluate, command_integrate, command_differentiate, command_getanisocoeff, command_getpoly, command_summary, command_getcoefficients, command_evalhierarchical_sparse, command_evalhierarchical_dense, command_gethsupport, command_getpointsindex, command_getneededindex }; // read grid or make a new grid if (not com.inside(makecoms, CArr<1>{command_makeexoquad})){ if (not readGridfile()) return false; } if (not checkSanePostRead()) return false; if (command == command_makequadrature) num_outputs = 0; if (com.inside(makecoms)){ auto llimits = readLimits(); auto aniso = readAnisotropic(); if (command == command_makeglobal or (command == command_makequadrature and OneDimensionalMeta::isGlobal(rule))){ grid.makeGlobalGrid(num_dimensions, num_outputs, depth, depth_type, rule, aniso, alpha, beta, customfilename.c_str(), llimits); }else if (command == command_makesequence){ grid.makeSequenceGrid(num_dimensions, num_outputs, depth, depth_type, rule, aniso, llimits); }else if (command == command_makefourier or (command == command_makequadrature and rule == rule_fourier)){ grid.makeFourierGrid(num_dimensions, num_outputs, depth, depth_type, aniso, llimits); }else if (command == command_makelocalp or (command == command_makequadrature and OneDimensionalMeta::isGlobal(rule))){ grid.makeLocalPolynomialGrid(num_dimensions, num_outputs, depth, order, rule, llimits); }else{ // wavelets grid.makeWaveletGrid(num_dimensions, num_outputs, depth, order, llimits); } setTransform(); } if (com.inside(makecoms) or command == command_setconformal) setConformal(); switch(command){ case command_update: grid.updateGrid(depth, depth_type, readAnisotropic()); break; case command_getdiffweights: case command_getinterweights: case command_evalhierarchical_dense: case command_evalhierarchical_sparse: case command_evaluate: case command_differentiate: processEvalLike(); break; case command_integrate: case command_gethsupport: case command_getanisocoeff: processOutputLike(); break; case command_getcoefficients: outputHierarchicalCoefficients(); break; case command_loadvalues: case command_load_construction: loadComputedValues(); break; case command_setcoefficients: setHierarchy(); break; case command_refine_clear: grid.clearRefinement(); if (grid.isUsingConstruction()) grid.finishConstruction(); break; case command_refine_merge: grid.mergeRefinement(); break; case command_using_construct: cout << "dynamic construction: " << ((grid.isUsingConstruction()) ? "enabled" : "disabled") << "\n"; break; case command_summary: grid.printStats(); break; case command_getneededindex: case command_getpointsindex: outputIndexes((command == command_getneededindex) ? output_points_mode::needed : output_points_mode::regular); break; case command_getpoly: getPoly(); break; case command_refine: case command_refine_aniso: case command_refine_surp: refineGrid(); break; case command_get_candidate_construction: getConstructedPoints(); break; default: break; } if ((com.inside(makecoms) or command == command_getpoints) and not com.inside(quadcoms)) outputPoints(output_points_mode::regular); if (com.inside(std::array{command_getneeded, command_refine, command_refine_aniso, command_refine_surp})) outputPoints(output_points_mode::needed); if (command == command_makequadrature or command == command_getquadrature) outputQuadrature(); if (not com.inside(constcoms)) writeGrid(); return pass_flag; } void TasgridWrapper::createExoticQuadrature(){ TasGrid::TasmanianSparseGrid weight_surrogate; weight_surrogate.read(weightfilename.c_str()); iassert(weight_surrogate.getNumDimensions() == 1, "the weight function surrogate must be one-dimensional"); iassert(weight_surrogate.getNumLoaded() > 0, "the weight function surrogate must have loaded values for interpolation"); ct = TasGrid::getExoticQuadrature(depth, shift, weight_surrogate, description.c_str(), is_symmetric_weight_function); if (not outfilename.empty()){ std::ofstream ofs(outfilename, std::ios::out | std::ios::trunc); ct.write(ofs); } if (printCout) ct.write(cout); } bool TasgridWrapper::readGridfile(){ try{ grid.read(gridfilename); }catch(std::runtime_error &e){ cerr << e.what() << "\n"; return false; } num_dimensions = grid.getNumDimensions(); num_outputs = grid.getNumOutputs(); rule = grid.getRule(); return true; } std::vector TasgridWrapper::readLimits() const{ if (levellimitfilename.empty()) return std::vector(); auto mat = readMatrix(levellimitfilename); iassert(mat.getNumStrips() == 1, "level limits file must contain only one row"); iassert(static_cast(mat.getStride()) == num_dimensions, (std::string("level limits file has wrong number of entries, expected: ") + std::to_string(num_dimensions) + " but found " + std::to_string(mat.getStride())).c_str()); std::vector llimits(num_dimensions); std::transform(mat.begin(), mat.end(), llimits.begin(), [](double x)->int{ return static_cast(x); }); return llimits; } std::vector TasgridWrapper::readAnisotropic() const{ if (anisofilename.empty()) return std::vector(); auto mat = readMatrix(anisofilename); iassert(mat.getNumStrips() == 1, "anisotropy file must contain only one row"); size_t expected_size = static_cast( (OneDimensionalMeta::getControurType(depth_type) == type_curved) ? 2*num_dimensions : num_dimensions); iassert(mat.getStride() == expected_size, (std::string("level limits file has wrong number of entries, expected: ") + std::to_string(expected_size) + " but found " + std::to_string(mat.getStride())).c_str()); std::vector weights(expected_size); std::transform(mat.begin(), mat.end(), weights.begin(), [](double x)->int{ return static_cast(x); }); return weights; } void TasgridWrapper::setTransform(){ if (transformfilename.empty()) return; auto mat = readMatrix(transformfilename); iassert(mat.getStride() == 2, "the matrix in the transform file must have exactly two columns"); iassert(mat.getNumStrips() == num_dimensions, (std::string("the domain transform expects ") + std::to_string(num_dimensions) + " rows but found " + std::to_string(mat.getNumStrips()) + " in the file: " + transformfilename).c_str()); std::vector transa((size_t) num_dimensions); std::vector transb((size_t) num_dimensions); for(int i=0; i(mat.getStride()) == num_dimensions, (std::string("conformal file for asin wrong number of entries, expected: ") + std::to_string(num_dimensions) + " but found " + std::to_string(mat.getStride())).c_str()); std::vector coeff(mat.getTotalEntries()); std::transform(mat.begin(), mat.end(), coeff.begin(), [](double x)->int{ return static_cast(x); }); grid.setConformalTransformASIN(coeff); } } void TasgridWrapper::outputPoints(output_points_mode mode) const{ if (outfilename.empty() and not printCout) return; int num_points = (mode == output_points_mode::needed) ? grid.getNumNeeded() : grid.getNumPoints(); auto points = (mode == output_points_mode::needed) ? grid.getNeededPoints() : grid.getPoints(); writeMatrix(outfilename, num_points, num_dimensions, points.data()); printMatrix(num_points, num_dimensions, points.data()); } void TasgridWrapper::outputIndexes(output_points_mode mode) const{ const int *p = (mode == output_points_mode::needed) ? grid.getNeededIndexes() : grid.getPointsIndexes(); int num_points = (mode == output_points_mode::needed) ? grid.getNumNeeded() : grid.getNumPoints(); Data2D pv(num_dimensions, num_points); std::transform(p, p + Utils::size_mult(num_points, num_dimensions), pv.getStrip(0), [](int i)->double{ return double(i); }); writeMatrix(outfilename, num_points, num_dimensions, pv.getStrip(0)); printMatrix(num_points, num_dimensions, pv.getStrip(0)); } void TasgridWrapper::outputQuadrature() const{ if (outfilename.empty() and not printCout) return; int num_points = grid.getNumPoints(); auto pnts = grid.getPoints(); Utils::Wrapper2D points(num_dimensions, pnts.data()); auto weights = grid.getQuadratureWeights(); Data2D combined(num_dimensions + 1, num_points); for(int i=0; i TasgridWrapper::verifiedRead(std::string const& filename, int expected_stride) const{ if (filename.empty() or expected_stride == 0) return Data2D(); Data2D x = readMatrix(filename); iassert(x.getStride() == static_cast(expected_stride), (std::string("the matrix in file ") + filename + " has " + std::to_string(x.getStride()) + " rows, but it should have " + std::to_string(expected_stride)).c_str()); return x; } void TasgridWrapper::processEvalLike() const{ int num_points = grid.getNumPoints(); if (not pass_flag) return; auto x = verifiedRead(xfilename, num_dimensions); Data2D result; switch(command){ case command_evaluate: result = Data2D(num_outputs, x.getNumStrips()); grid.evaluateBatch(x.data(), x.getNumStrips(), result.data()); break; case command_differentiate: result = Data2D(num_outputs * num_dimensions, x.getNumStrips()); #pragma omp parallel for for (int i=0; i(num_points, x.getNumStrips()); #pragma omp parallel for for(int i=0; i(num_points * num_dimensions, x.getNumStrips()); #pragma omp parallel for for(int i=0; i(num_points * (grid.isFourier() ? 2 : 1), x.getNumStrips()); grid.evaluateHierarchicalFunctions(x.data(), x.getNumStrips(), result.data()); break; case command_evalhierarchical_sparse: { // scope is needed to declare sparse variables internal_sparse_matrix matrix(num_points); grid.evaluateSparseHierarchicalFunctions(x.release(), matrix.pntr, matrix.indx, matrix.vals); matrix.write(outfilename, useASCII); matrix.write(printCout); return; // after this, there is output section but invalid for this command } break; default: throw std::runtime_error("ERROR: internal problem, processEvalLike() called with wrong command"); break; } writeMatrix(outfilename, result); printMatrix(result); } void TasgridWrapper::processOutputLike() const{ // returns data and updates the above through capture Data2D result; switch(command){ case command_integrate: if (not pass_flag) return; result = Data2D(1, grid.getNumOutputs(), grid.integrate()); break; case command_gethsupport: result = Data2D(grid.getNumDimensions(), grid.getNumPoints(), grid.getHierarchicalSupport()); break; case command_getanisocoeff: if (not pass_flag) return; { std::vector ab = grid.estimateAnisotropicCoefficients(depth_type, (grid.isGlobal() and ref_output == -1) ? 0 : ref_output); std::vector temp(ab.size()); std::transform(ab.begin(), ab.end(), temp.begin(), [](int i)->double{ return double(i); }); result = Data2D(1, grid.getNumDimensions() * ((OneDimensionalMeta::getControurType(depth_type) == type_curved) ? 2 : 1), std::move(temp)); } break; default: throw std::runtime_error("invalid command for processOutputLike() method"); } writeMatrix(outfilename, result); printMatrix(result); } void TasgridWrapper::outputHierarchicalCoefficients() const{ const double *coeff = grid.getHierarchicalCoefficients(); int num_points = grid.getNumPoints(); if (grid.isFourier()){ // use interwoven format for complex coefficients Data2D coeff_fourier(2 * num_outputs, num_points); Utils::Wrapper2D real(num_outputs, coeff); Utils::Wrapper2D imag(num_outputs, real.getStrip(num_points)); for(int p=0; p points; if (outfilename.empty() && (printCout == false)) return; if (useNeeded){ num_p = grid.getNumNeeded(); points = grid.getNeededPoints(); }else{ num_p = grid.getNumPoints(); points = grid.getPoints(); } writeMatrix(outfilename, num_p, num_d, points.data()); printMatrix(num_p, num_d, points.data()); } void TasgridWrapper::refineGrid(){ auto llimits = readLimits(); TypeCommand effective_command = command; if (command == command_refine){ if (grid.isGlobal() || grid.isSequence()){ effective_command = command_refine_aniso; }else{ effective_command = command_refine_surp; } } if (effective_command == command_refine_aniso){ if (min_growth < 1) min_growth = 1; if (grid.isGlobal() and ref_output == -1) ref_output = 0; grid.setAnisotropicRefinement(depth_type, min_growth, ref_output, llimits); }else{ // using surplus refinement Data2D scale; if (not valsfilename.empty() and (grid.isLocalPolynomial() or grid.isWavelet())){ scale = readMatrix(valsfilename); iassert(scale.getNumStrips() == grid.getNumPoints(), "the number of weights must match the number of points"); if (ref_output == -1) iassert(scale.getStride() == 1, "the number of weights must match the number of outputs"); if (ref_output > -1) iassert(scale.getStride() == (size_t) grid.getNumOutputs(), "there must be one weight per output"); } if (not pass_flag) return; if (grid.isGlobal() and ref_output == -1) ref_output = 0; if (grid.isGlobal() and grid.isSequence()){ grid.setSurplusRefinement(tolerance, ref_output, llimits); }else{ grid.setSurplusRefinement(tolerance, tref, ref_output, llimits, scale.release()); } } } void TasgridWrapper::getConstructedPoints(){ if (!grid.isUsingConstruction()) grid.beginConstruction(); auto llimits = readLimits(); std::vector points; if (grid.isLocalPolynomial() || grid.isWavelet()){ Data2D scale; if (!valsfilename.empty()){ scale = readMatrix(valsfilename); iassert(scale.getNumStrips() == grid.getNumPoints(), "the number of weights must match the number of points"); if (ref_output == -1) iassert(scale.getStride() == (size_t) grid.getNumOutputs(), "the number of weights must match the number of outputs"); else iassert(scale.getStride() == 1, "there must be one weight per output"); if (not pass_flag) return; } points = grid.getCandidateConstructionPoints(tolerance, tref, ref_output, llimits, scale.release()); }else{ if (not anisofilename.empty()){ auto weights = readAnisotropic(); points = grid.getCandidateConstructionPoints(depth_type, weights, llimits); }else{ points = grid.getCandidateConstructionPoints(depth_type, ref_output, llimits); } } writeMatrix(outfilename, points.size() / num_dimensions, num_dimensions, points.data()); printMatrix(points.size() / num_dimensions, num_dimensions, points.data()); } void TasgridWrapper::getPoly(){ bool integrate = ((depth_type == type_iptotal) || (depth_type == type_ipcurved) || (depth_type == type_iptensor) || (depth_type == type_iphyperbolic)); std::vector poly = grid.getGlobalPolynomialSpace(integrate); std::vector double_poly(poly.size()); std::transform(poly.begin(), poly.end(), double_poly.begin(), [](int x)->double{ return static_cast(x); }); writeMatrix(outfilename, (int) double_poly.size() / num_dimensions, num_dimensions, double_poly.data()); printMatrix((int) double_poly.size() / num_dimensions, num_dimensions, double_poly.data()); } void TasgridWrapper::setHierarchy(){ auto vals = readMatrix(valsfilename); iassert(vals.getNumStrips() == grid.getNumPoints(), (std::string("grid is awaiting ") + std::to_string(grid.getNumPoints()) + " hierarchical surpluses, but " + valsfilename + " specifies " + std::to_string(vals.getNumStrips())).c_str()); if (grid.isFourier()) iassert((vals.getStride() == (size_t) (2 * grid.getNumOutputs())), (std::string("fourier grid is set for ") + std::to_string(grid.getNumOutputs()) + " outputs, but " + valsfilename + " specifies " + std::to_string(vals.getStride())).c_str()); else iassert((vals.getStride() == (size_t) grid.getNumOutputs()), (std::string("grid is set for ") + std::to_string(grid.getNumOutputs()) + " outputs, but " + valsfilename + " specifies " + std::to_string(vals.getStride())).c_str()); if (not pass_flag) return; grid.setHierarchicalCoefficients(vals.release()); } template Data2D readMatrixFromOpen(std::istream &is){ int rows = IO::readNumber(is); int cols = IO::readNumber(is); return Data2D(cols, rows, IO::readVector(is, Utils::size_mult(cols, rows))); } Data2D TasgridWrapper::readMatrix(std::string const &filename) const{ Data2D matrix; if (filename.empty()) return matrix; std::ifstream ifs; ifs.open(filename, std::ios::in | std::ios::binary); iassert(ifs.good(), (std::string("could not open file ") + filename).c_str()); if (not pass_flag) return matrix; char tsg[3] = {'A', 'A', 'A'}; ifs.read(tsg, 3*sizeof(char)); if ((tsg[0] == 'T') && (tsg[1] == 'S') && (tsg[2] == 'G')){ matrix = readMatrixFromOpen(ifs); }else{ // not a binary file ifs.close(); ifs.open(filename); matrix = readMatrixFromOpen(ifs); } if (matrix.empty()) cerr << "WARNING: empty file " << filename << "\n"; return matrix; } void TasgridWrapper::writeMatrix(std::string const &filename, int rows, int cols, const double mat[]) const{ if (filename.empty()) return; size_t cols_t = (size_t) cols; std::ofstream ofs; if (useASCII){ Utils::Wrapper2D matrix(cols, mat); ofs.open(filename); ofs << rows << " " << cols << "\n"; ofs.precision(17); ofs << std::scientific; for(int i=0; i matrix(cols, mat); for(int i=0; i(r[0], r[1]); for(size_t j=1; j(r[2*j], r[2*j + 1]); }else{ cout << setw(25) << r[0]; for(size_t j=1; j readLimits() const; std::vector readAnisotropic() const; void createExoticQuadrature(); void setTransform(); void setConformal(); void outputPoints(output_points_mode mode) const; void outputIndexes(output_points_mode mode) const; void outputQuadrature() const; void writeGrid() const; void outputPoints(bool useNeeded) const; void outputHierarchicalCoefficients() const; Data2D verifiedRead(std::string const& filename, int expected_stride) const; void processEvalLike() const; void processOutputLike() const; void loadComputedValues(); void setHierarchy(); void refineGrid(); void getPoly(); void getConstructedPoints(); Data2D readMatrix(std::string const &filename) const; void writeMatrix(std::string const &filename, int rows, int cols, const double mat[]) const; void printMatrix(int rows, int cols, const double mat[], bool isComplex = false) const; // Overloads. template inline void writeMatrix(std::string const &filename, const Data2D &mat) const { writeMatrix(filename, mat.getNumStrips(), mat.getStride(), mat.data()); } template inline void printMatrix(const Data2D &mat, bool isComplex = false) const { printMatrix(mat.getNumStrips(), mat.getStride(), mat.data(), isComplex); } private: TasmanianSparseGrid grid; CustomTabulated ct; TypeCommand command; int num_dimensions, num_outputs, depth, order; TypeDepth depth_type; TypeOneDRule rule; TypeConformalMap conformal; double alpha, beta; bool set_alpha, set_beta; double tolerance; bool set_tolerance; int ref_output, min_growth; TypeRefinement tref; bool set_tref; std::string gridfilename; std::string outfilename; std::string valsfilename; std::string xfilename; std::string anisofilename; std::string transformfilename; std::string conformalfilename; std::string customfilename; std::string levellimitfilename; bool printCout; bool useASCII; int set_gpuid; double shift; bool set_shift; std::string weightfilename; std::string description; bool is_symmetric_weight_function; mutable bool pass_flag; // report internal errors }; #endif TASMANIAN-8.1/Tasgrid/tasgrid_main.cpp000066400000000000000000001577401470551176200174650ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "gridtestExternalTests.hpp" #include "tasgridWrapper.hpp" using namespace std; using namespace TasGrid; enum TypeHelp{ help_generic, help_command, help_listtypes }; void printHelp(TypeHelp ht = help_generic, TypeCommand com = command_none); int main(int argc, const char ** argv){ //cout << " Phruuuuphrrr \n"; // this is the sound that the Tasmanian devil makes std::deque args = stringArgs(argc, argv); if (args.empty()){ cerr << "ERROR: no command specified\n\n"; printHelp(); return 1; } // basic help if (hasHelp(args.front())){ printHelp(); return 0; } // print log files if(args.front() == "-log"){ show_log(); return 0; } if(args.front() == "-cmakelog" or args.front() == "--cmakelog" or args.front() == "-cmake"){ show_cmake_log(); return 0; } // basic info, i.e., version, license, parallel support if (hasInfo(args.front())){ cout << "Tasmanian Sparse Grids version: " << TasmanianSparseGrid::getVersion() << "\n"; if ((std::string(TasmanianSparseGrid::getGitCommitHash()).compare("Tasmanian git hash is not available here") != 0) && (std::string(TasmanianSparseGrid::getGitCommitHash()).find("Release") != 0)){ cout << " git commit hash: " << TasmanianSparseGrid::getGitCommitHash() << "\n"; cout << " cmake cxx flags: " << TasmanianSparseGrid::getCmakeCxxFlags() << "\n"; } cout << " license: " << TasmanianSparseGrid::getLicense() << "\n"; if (TasmanianSparseGrid::isOpenMPEnabled()){ cout << " OpenMP multithreading: Enabled\n"; }else{ cout << " OpenMP multithreading: Disabled\n"; } std::string gpu_backend = "none"; if (TasmanianSparseGrid::isCudaEnabled()) gpu_backend = "CUDA"; if (TasmanianSparseGrid::isHipEnabled()) gpu_backend = "ROCm/HIP"; if (TasmanianSparseGrid::isDpcppEnabled()) gpu_backend = "oneAPI/DPC++"; cout << " GPU backend framework: " << gpu_backend << "\n"; cout << " Available acceleration: "; bool anyAcc = false, anyGPU = false; if (TasmanianSparseGrid::isAccelerationAvailable(accel_cpu_blas)){ cout << AccelerationMeta::getIOAccelerationString(accel_cpu_blas); anyAcc = true; } if (TasmanianSparseGrid::isAccelerationAvailable(accel_gpu_cublas)){ cout << " " << AccelerationMeta::getIOAccelerationString(accel_gpu_cublas); anyAcc = true; anyGPU = true; } if (TasmanianSparseGrid::isAccelerationAvailable(accel_gpu_cuda)){ cout << " " << AccelerationMeta::getIOAccelerationString(accel_gpu_cuda); anyAcc = true; anyGPU = true; } if (TasmanianSparseGrid::isAccelerationAvailable(accel_gpu_magma)){ cout << " " << AccelerationMeta::getIOAccelerationString(accel_gpu_magma); anyAcc = true; anyGPU = true; } if (!anyAcc){ cout << " none"; } cout << "\n"; if (anyGPU){ int numGPUs = TasmanianSparseGrid::getNumGPUs(); if (numGPUs > 0){ cout << " Available GPUs:" << "\n"; for(int i=0; i= TasmanianSparseGrid::getNumGPUs())){ cerr << "ERROR: -gpuid " << gpuid << " is not a valid gpuid!\n"; cerr << " see ./tasgrid -v for a list of detected GPUs.\n"; return 1; } } args.pop_front(); } ExternalTester tester(1000); tester.setGPUID(gpuid); bool pass = true; if (debug){ tester.debugTest(); }else if (debugII){ tester.debugTestII(); }else{ if (verbose) tester.setVerbose(true); if (seed_reset) tester.resetRandomSeed(); pass = tester.Test(test); } return (pass) ? 0 : 1; } // doing actual work with a grid // get the command TasgridWrapper wrap; auto command = TasgridWrapper::hasCommand(args.front()); if (command == command_none){ cout << "ERROR: unknown command " << args.front() << "\n"; printHelp(); return 1; } wrap.setCommand(command); // parse the parameters args.pop_front(); while(!args.empty()){ if (hasHelp(args.front())){ printHelp(help_command, command); return 0; }else if (args.front() == "-xf" || args.front() == "-xfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide file name with x values!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setXFilename(args.front()); }else if (args.front() == "-vf" || args.front() == "-valsfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide values file name!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setValsFilename(args.front()); }else if (args.front() == "-of" || args.front() == "-outputfile" || args.front() == "-outfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide output file name!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setOutFilename(args.front()); }else if (args.front() == "-gf" || args.front() == "-gridfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide grid file name!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setGridFilename(args.front()); }else if (args.front() =="-ascii"){ wrap.setUseASCII(true); }else if (args.front() == "-af" || args.front() == "-anisotropyfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide anisotropy file name!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setAnisoFilename(args.front()); }else if (args.front() == "-tf" || args.front() == "-transformfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide transform file name!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setTransformFilename(args.front()); }else if (args.front() == "-conformalfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide conformal transform file name!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setConformalFilename(args.front()); }else if (args.front() == "-lf" || args.front() == "-levellimitsfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide level limits file name!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setLevelLimitsFilename(args.front()); }else if (args.front() == "-cf" || args.front() == "-customfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide custom file name!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setCustomFilename(args.front()); }else if (args.front() == "-print" || args.front() == "-p"){ wrap.setPrintPoints(true); }else if (args.front() == "-dim" || args.front() == "-dimensions"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide number of dimensions!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setNumDimensions(std::stoi(args.front())); }else if (args.front() == "-out" || args.front() == "-outputs"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide number of outputs!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setNumOutputs(std::stoi(args.front())); }else if (args.front() == "-dt" || args.front() == "-depth"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid depth!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setNumDepth(std::stoi(args.front())); }else if (args.front() == "-or" || args.front() == "-order"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid order!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setOrder(std::stoi(args.front())); }else if (args.front() == "-tt" || args.front() == "-type"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid depth type!!! For help see: ./tasgrid -help\n\n"; return 1; } TypeDepth depth_type = IO::getDepthTypeString(args.front()); if (depth_type == type_none){ cerr << "ERROR: " << args.front() << " is not a valid type!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setDepthType(depth_type); }else if (args.front() == "-1d" || args.front() == "-onedim"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid -onedim!!! For help see: ./tasgrid -help\n\n"; return 1; } TypeOneDRule rule = IO::getRuleString(args.front()); if (rule == rule_none){ cerr << "ERROR: " << args.front() << " is not a valid rule!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setRule(rule); }else if (args.front() == "-ct" || args.front() == "-conformaltype"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid -conformaltype!!! For help see: ./tasgrid -help\n\n"; return 1; } TypeConformalMap conformal_type = TasgridWrapper::getConfromalType(args.front().c_str()); if (conformal_type == conformal_none){ cerr << "ERROR: " << args.front() << " is not a valid conformal type!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setConformalType(conformal_type); }else if (args.front() == "-alpha"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid -alpha!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setAlpha(std::stof(args.front())); }else if (args.front() == "-beta"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid -beta!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setBeta(std::stof(args.front())); }else if (args.front() == "-tol" || args.front() == "-tolerance"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid -tolerance!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setTolerance(std::stof(args.front())); }else if (args.front() == "-rout" || args.front() == "-refout"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid -refout!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setRefOutput(std::stoi(args.front())); }else if (args.front() == "-ming" || args.front() == "-mingrowth"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid -mingrowth!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setMinGrowth(std::stoi(args.front())); }else if (args.front() == "-rt" || args.front() == "-reftype"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid depth type!!! For help see: ./tasgrid -help\n\n"; return 1; } TypeRefinement ref = IO::getTypeRefinementString(args.front()); if (ref == refine_none){ cerr << "ERROR: " << args.front() << " is not a valid refinement type!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setTypeRefinement(ref); }else if (args.front() == "-gpu" || args.front() == "-gpuid"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid -gpuid For help see: ./tasgrid -help\n\n"; return 1; } wrap.setGPID(std::stoi(args.front())); }else if (args.front() == "-shift"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide valid -shift!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setShift(std::stof(args.front())); }else if (args.front() == "-wf" || args.front() == "-weightfile"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide weight file name!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setWeightFilename(args.front()); }else if (args.front() == "-desc" || args.front() == "-description"){ args.pop_front(); if (args.empty()){ cerr << "ERROR: must provide description!!! For help see: ./tasgrid -help\n\n"; return 1; } wrap.setDescription(args.front()); }else if (args.front() == "-symm" || args.front() == "-symmetric"){ wrap.setIsSymmetric(true); }else if (command == command_summary || command == command_using_construct){ wrap.setGridFilename(args.front()); }else{ cout << "WARNING: ignoring unknown option: " << args.front() << "\n"; } args.pop_front(); } if (!wrap.executeCommand()){ return 1; } return 0; } void printHelp(TypeHelp ht, TypeCommand com){ if (ht == help_generic){ cout << R"help( Usage: tasgrid ... Commands Shorthand Action -help -h,--help show verbose help options -version -v,-info show version and general info of enabled capabilities -log show the install log -cmakelog -cmake show the verbose list of cmake options -listtypes -lt list accepted grid types and 1-D rules -test perform a number of internal tests -makeglobal -mg make a grid from a global rule -makesequence -ms make a grid from a sequence rule -makelocalpoly -mp make a grid from a local polynomial rule -makewavelet -mw make a grid from a wavelet rule -makefourier -mf make a grid from a Fourier rule -makequadrature -mq make a quadrature -makeexoquad -meq make an exotic quadrature -makeupdate -mu updates an existing global/sequence/fourier grid -setconformal -sc set conformal domain transform -getquadrature -gq output quadrature weights and points -getinterweights -gi output the interpolation weights -getdiffweights -gd output the differentiation weights -getpoints -gp output the points -getneededpoints -gn outputs the points needing values to build an interpolant -loadvalues -l load the values of the interpolated function -evaluate -e evaluates the interpolant -evalhierarchyd -ehd evaluates the hierarchical basis (dense output) -evalhierarchys -ehs evaluates the hierarchical basis (sparse output) -gethsupport -ghsup get the hierarchical support -integrate -i output the integral -differentiate -d differentiates the interpolant -getanisotropy -ga estimates the anisotropic coefficients -refineaniso -ra refines the grid -refinesurp -rs refines the grid -refine -r refines the grid -cancelrefine -cr discards the last refinement (unless values are already loaded) -mergerefine -mr combines the loaded and needed points and discards the loaded values -using-construct prints simple string indicating whether dynamic construction is in use -getconstructpnts -gcp get points for dynamic construction -loadconstructed -lcp load points for dynamic construction -getcoefficients -gc get the hierarchical coefficients of the grid -setcoefficients -sc set the hierarchical coefficients of the grid -getpoly get polynomial space -summary -s writes short description Options Shorthand Value Action -help help display verbose information about this command -dimensions -dim set the number of dimensions -outputs -out set the number of outputs -depth -dt set the depth of the grid (e.g. levels) -type -tt set the type of the grid -conformaltype -tt set the type of the transformation -onedim -1d set the one dimensional rule -order -or set the order for local polynomial and wavelet basis -alpha the alpha parameter for Gegenbauer/Jacobi/Laguerre/Hermite quadrature -beta the beta parameter for Jacobi quadrature -tolerance -tol set the tolerance for the refinement -refout -rout select the output to use for the refinement -mingrowth -ming minimum number of new points -reftype -rt set the type of refinement -gridfile -gf set the name for the grid file -xfile -xf set the name for the file with points -valsfile -vf set the name for the file with values -outputfile -of set the name for the output file -anisotropyfile -af set the anisotropic weights -transformfile -tf set the transformation of the domain -conformalfile -tf set the conformal transformation of the domain -levellimitsfile -lf set the limits for the levels -customfile -cf set the file with the custom-tabulated rule -gpuid set the gpu to use for evaluations -print -p print to standard output -ascii use ASCII grid file format )help"; }else if (ht == help_command){ switch(com){ case command_makeglobal: cout << R"help( Commands Shorthand Action -makeglobal -mg make a grid from a global rule Accepted options: Options Required Value Action -dimensions yes set the number of dimensions -outputs yes set the number of outputs -depth yes set the depth of the grid (e.g. levels) -type yes set the type of the grid -onedim yes set the one dimensional rule must use a global rule (see manual) -alpha sometimes the alpha parameter for Gegenbauer/Jacobi/Laguerre/Hermite quadrature required for those rules -beta sometimes the beta parameter for Jacobi quadrature required for Jacobi rule -gridfile no set the name for the grid file -outputfile no set the name for the output file -anisotropyfile no set the anisotropic weights -transformfile no set the transformation of the domain -customfile sometimes set the file with the custom-tabulated rule -conformaltype no set the type of the map -conformalfile no set the conformal transformation of the domain required for custom-tabulated rule -levellimitsfile no set the limits for the levels -print no print to standard output -ascii use ASCII grid file format Note: -outputfile or -print output the points of the grid Note: at least one of -gridfile, -outputfile, or -print must be specified, otherwise the command has no output )help"; break; case command_makesequence: cout << R"help( Commands Shorthand Action -makesequence -ms make a grid from a sequence rule Accepted options: Options Required Value Action -dimensions yes set the number of dimensions -outputs yes set the number of outputs -depth yes set the depth of the grid (e.g. levels) -type yes set the type of the grid -onedim yes set the one dimensional rule must use a sequence rule (see manual) -gridfile no set the name for the grid file -outputfile no set the name for the output file -anisotropyfile no set the anisotropic weights -transformfile no set the transformation of the domain -conformaltype no set the type of the map -conformalfile no set the conformal transformation of the domain -levellimitsfile no set the limits for the levels -print no print to standard output -ascii use ASCII grid file format Note: -outputfile or -print output the points of the grid Note: at least one of -gridfile, -outputfile, or -print must be specified, otherwise the command has no output )help"; break; case command_makelocalp: cout << R"help( Commands Shorthand Action -makelocalpoly -mp make a grid from a local polynomial rule Accepted options: Options Required Value Action -dimensions yes set the number of dimensions -outputs yes set the number of outputs -depth yes set the depth of the grid (e.g. levels) -order yes set the order for local polynomial basis -onedim yes set the one dimensional rule must use a local polynomial rule (see manual) -gridfile no set the name for the grid file -outputfile no set the name for the output file -transformfile no set the transformation of the domain -conformaltype no set the type of the map -conformalfile no set the conformal transformation of the domain -levellimitsfile no set the limits for the levels -print no print to standard output -ascii use ASCII grid file format Note: -outputfile or -print output the points of the grid Note: at least one of -gridfile, -outputfile, or -print must be specified, otherwise the command has no output )help"; break; case command_makewavelet: cout << R"help( Commands Shorthand Action -makewavelet -mw make a grid from a wavelet rule Accepted options: Options Required Value Action -dimensions yes set the number of dimensions -outputs yes set the number of outputs -depth yes set the depth of the grid (e.g. levels) -order yes set the order for the wavelet basis -gridfile no set the name for the grid file -outputfile no set the name for the output file -transformfile no set the transformation of the domain -conformaltype no set the type of the map -conformalfile no set the conformal transformation of the domain -levellimitsfile no set the limits for the levels -print no print to standard output -ascii use ASCII grid file format Note: -outputfile or -print output the points of the grid Note: at least one of -gridfile, -outputfile, or -print must be specified, otherwise the command has no output )help"; break; case command_makefourier: cout << R"help( Commands Shorthand Action -makefourier -mf make a grid from a Fourier rule Accepted options: Options Required Value Action -dimensions yes set the number of dimensions -outputs yes set the number of outputs -depth yes set the depth of the grid (e.g. levels) -type yes set the type of the grid -gridfile no set the name for the grid file -outputfile no set the name for the output file -anisotropyfile no set the anisotropic weights -transformfile no set the transformation of the domain -conformaltype no set the type of the map -conformalfile no set the conformal transformation of the domain -levellimitsfile no set the limits for the levels -print no print to standard output -ascii use ASCII grid file format Note: -outputfile or -print output the points of the grid Note: at least one of -gridfile, -outputfile, or -print must be specified, otherwise the command has no output )help"; break; case command_makequadrature: cout << R"help( Commands Shorthand Action -makequadrature -mq make a quadrature Accepted options: Options Required Value Action -dimensions yes set the number of dimensions -depth yes set the depth of the grid (e.g. levels) -type sometimes set the type of the grid required only for global rules (see manual) -order sometimes set the order for local polynomial basis required only for local polynomial and wavelet (see manual) -onedim yes set the one dimensional rule can use any rule (see manual) -alpha sometimes the alpha parameter for Gegenbauer/Jacobi/Laguerre/Hermite quadrature required for those rules -beta sometimes the beta parameter for Jacobi quadrature required for Jacobi rule -outputfile no set the name for the output file -anisotropyfile no set the anisotropic weights -transformfile no set the transformation of the domain -customfile sometimes set the file with the custom-tabulated rule -conformaltype no set the type of the map -conformalfile no set the conformal transformation of the domain required for custom-tabulated rule -print no print to standard output Note: -outputfile or -print output the points and weights of the grid Note: at least one of -outputfile, or -print must be specified, otherwise the command has no output )help"; break; case command_makeexoquad: cout << R"help( Commands Shorthand Action -makeexoquad -meq make an exotic quadrature Accepted options: Options Required Value Action -depth yes set the depth of the grid (e.g. levels) -shift yes set the shift of the weight function -weightfile yes set the name of the file containing a surrogate/interpolant of the weight function must be a TasmanianSparseGrid in ASCII format -description yes short description of the quadrature -symmetric no declare that the weight function is symmetric endl -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the points and weights of the grid Note: at least one of -outputfile, or -print must be specified, otherwise the command has no output )help"; break; case command_update: cout << R"help( Commands Shorthand Action -makeupdate -mu updates a new global or sequence grid Accepted options: Options Required Value Action -depth yes set the depth of the grid (e.g. levels) -type yes set the type of the grid -anisotropyfile no set the anisotropic weights -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the new points of the grid )help"; break; case command_setconformal: cout << R"help( Commands Shorthand Action -setconformal -sc set conformal transformation Accepted options: Options Required Value Action -conformaltype yes set the type of the map -conformalfile yes set the conformal transformation of the domain )help"; break; case command_getquadrature: cout << R"help( Commands Shorthand Action -getquadrature -gq make a quadrature Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the points and weights of the grid Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_getcoefficients: cout << R"help( Commands Shorthand Action -getcoefficients -gc get the hierarchical coefficients Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the hierarchical coefficients of the sparse grid Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_setcoefficients: cout << R"help( Commands Shorthand Action -setcoefficients -sc set the hierarchical coefficients Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the hierarchical coefficients of the sparse grid Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_getinterweights: cout << R"help( Commands Shorthand Action -getinterweights -gi output the interpolation weights Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -xfile yes set the name for the file with points -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the interpolation weight for each point in the xfile, see equation (1.2) in the manual Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_getdiffweights: cout << R"help( Commands Shorthand Action -getdiffweights -gd output the differentiation weights Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -xfile yes set the name for the file with points -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the differentiation weight for each point in the xfile Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_getpoints: cout << R"help( Commands Shorthand Action -getpoints -gp output the points Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the points of the grid Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_getneeded: cout << R"help( Commands Shorthand Action -getneededpoints -gn outputs the points needing values to build an interpolant Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the new points of the grid Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_loadvalues: cout << R"help( Commands Shorthand Action -loadvalues -l provides values of the model outputs at the needed grid points Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -valsfile -vf set the name for the file with values Note: the -valsfile must contains rows equal to the number of needed points or (if there are no needed points) the number of loaded points the number of columns must match the number of outputs set for the grid )help"; break; case command_evaluate: cout << R"help( Commands Shorthand Action -evaluate -e evaluates the interpolant Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -xfile yes set the name for the file with points -gpuid no set the gpu to use for evaluations -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output values of the interpolant at the points specified in the xfile Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_evalhierarchical_dense: cout << R"help( Commands Shorthand Action -evalhierarchyd -ehd evaluates the hierarchical basis (dense output) Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -xfile yes set the name for the file with points -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output values of the hierarchical basis functions in the xfile Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_evalhierarchical_sparse: cout << R"help( Commands Shorthand Action -evalhierarchys -ehs evaluates the hierarchical basis (sparse output) Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -xfile yes set the name for the file with points -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output values of the hierarchical basis functions in the xfile Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_gethsupport: cout << R"help( Commands Shorthand Action -gethsupport -ghsup get the hierarchical support Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -outputfile no set the name for the output file -print no print to standard output Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_integrate: cout << R"help( Commands Shorthand Action -integrate -i output the integral Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the integral if the loaded function, see equation (1.3) in the manual Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_differentiate: cout << R"help( Commands Shorthand Action -differentiate -d differentiates the interpolant Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -xfile yes set the name for the file with points -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print derivative (Jacobian matrix) of the interpolant at the points specified in the xfile Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_getanisocoeff: cout << R"help( Commands Shorthand Action -getanisotropy -ga estimates the anisotropic coefficients Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -type yes set the type of anisotropic coefficients -refout sometimes select the output to use required by global grids only -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the estimated anisotropic coefficients )help"; break; case command_refine_aniso: cout << R"help( Commands Shorthand Action -refineaniso -ra refines the grid Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -type yes set the type of anisotropic refinement -mingrowth no minimum number of new points (defaults to 1) -refout sometimes select the output to use for the refinement required by global grids, for sequence grids defaults to -1 (use all outputs) -levellimitsfile no set the limits for the levels -outputfile no set the name for the output file -print no print to standard output -ascii use ASCII grid file format Note: -outputfile or -print output the new points of the grid )help"; break; case command_refine_surp: cout << R"help( Commands Shorthand Action -refinesurp -rs refines the grid Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -tolerance yes set the tolerance for the refinement -reftype sometimes set the type of refinement required by local polynomial and wavelet grids -refout sometimes select the output to use for the refinement required by global grids, for sequence grids defaults to -1 (use all outputs) -levellimitsfile no set the limits for the levels -valsfile no set the correction weights for the surpluses -outputfile no set the name for the output file -print no print to standard output -ascii use ASCII grid file format Note: -outputfile or -print output the new points of the grid )help"; break; case command_refine: cout << R"help( Commands Shorthand Action -refine -r refines the grid -refine calls -refineaniso for Global and Sequence grids and -refinesurp otherwise see "-refineaniso help" or "-refinesurp help" for the corresponding accepted options Note: -outputfile or -print output the new points of the grid )help"; break; case command_refine_clear: cout << R"help( Commands Shorthand Action -cancelrefine -cr discards the last refinement (unless values are already loaded) Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -ascii use ASCII grid file format )help"; break; case command_refine_merge: cout << R"help( Commands Shorthand Action -mergerefine -mr merges the loaded and needed points and discards any loaded values Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -ascii use ASCII grid file format )help"; break; case command_using_construct: cout << R"help( Commands Action -using-construct writes short string indicating whether dynamic construction is on Accepted options: Options Required Value Action -gridfile yes set the name for the grid file Note that 'tasgrid -using-construct ' is also accepted )help"; break; case command_get_candidate_construction: cout << R"help( Commands Shorthand Action -getconstructpnts -gcp get points for dynamic construction Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -refout sometimes select the output to use for the refinement -anisotropyfile sometimes set the anisotropic weights -levellimitsfile no set the limits for the levels -outputfile no set the name for the output file -print no print to standard output -ascii use ASCII grid file format )help"; break; case command_load_construction: cout << R"help( Commands Shorthand Action -loadconstructed -lcp load points for dynamic construction Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -xfile yes set the name for the file with points -valsfile yes set the name for the file with values )help"; break; case command_getpoly: cout << R"help( Commands Shorthand Action -getpoly get polynomial space Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -type yes specifies whether to use quadrature or interpolation -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print output the polynomial indexes )help"; break; case command_summary: cout << R"help( Commands Shorthand Action -summary -s writes short description Accepted options: Options Required Value Action -gridfile yes set the name for the grid file Note that 'tasgrid -s ' is also accepted )help"; break; case command_getpointsindex: case command_getneededindex: cout << R"help( Commands Action -getpointsindexes returns the integer multi-index set of the points -getneededindexes returns the integer multi-index set of the needed points Note: these commands exist primarily for debugging purposes Accepted options: Options Required Value Action -gridfile yes set the name for the grid file -outputfile no set the name for the output file -print no print to standard output Note: -outputfile or -print derivative (Jacobian matrix) of the interpolant at the points specified in the xfile Note: at least one of -outputfile or -print must be specified, otherwise the command has no output )help"; break; case command_none: throw std::runtime_error("ERROR: incorrect command for help"); } }else if (ht == help_listtypes){ cout << R"help( This only lists the strings associated with each option for spelling purposes. Refer to the manual for details about each type. List of global grids types: level curved hyperbolic tensor iptotal ipcurved iphyperbolic iptensor qptotal qpcurved qphyperbolic qptensor List of global grids rules: chebyshev chebyshev-odd clenshaw-curtis clenshaw-curtis-zero leja leja-odd rleja rleja-odd rleja-double2 rleja-double4 rleja-shifted rleja-shifted-even max-lebesgue max-lebesgue-odd min-lebesgue min-lebesgue-odd min-delta min-delta-odd fejer2 gauss-legendre gauss-legendre-odd gauss-patterson custom-tabulated gauss-gegenbauer gauss-gegenbauer-odd gauss-jacobi gauss-jacobi-odd gauss-laguerre gauss-laguerre-odd gauss-hermite gauss-hermite-odd gauss-chebyshev1 gauss-chebyshev1-odd gauss-chebyshev2 gauss-chebyshev2-odd List of sequence grids rules: leja rleja rleja-shifted max-lebesgue min-lebesgue min-delta List of local polynomial grids rules: localp localp-zero semi-localp localp-boundary List of local wavelet grids rules: wavelet List of local polynomial and wavelet refinement types: classic parents direction fds List of conformal maps: asin )help"; } } TASMANIAN-8.1/Testing/000077500000000000000000000000001470551176200143225ustar00rootroot00000000000000TASMANIAN-8.1/Testing/CMakeLists.test.cmake000066400000000000000000000032021470551176200202760ustar00rootroot00000000000000cmake_minimum_required(VERSION @CMAKE_MAJOR_VERSION@.@CMAKE_MINOR_VERSION@) cmake_policy(VERSION @CMAKE_MAJOR_VERSION@.@CMAKE_MINOR_VERSION@) project(TasmanianTesting VERSION @Tasmanian_VERSION_MAJOR@.@Tasmanian_VERSION_MINOR@.@Tasmanian_VERSION_PATCH@ LANGUAGES @Tasmanian_langs@) enable_testing() message(STATUS "Tasmanian post-installation testing") # the following find_package() command will help us locate an existing Tasmanian installation. find_package(Tasmanian @Tasmanian_VERSION_MAJOR@.@Tasmanian_VERSION_MINOR@.@Tasmanian_VERSION_PATCH@ PATHS "@Tasmanian_final_install_path@" REQUIRED @Tasmanian_components@) add_subdirectory("@Tasmanian_final_install_path@/share/Tasmanian/examples" examples_cxx) add_test(SparseGrids "${CMAKE_CURRENT_BINARY_DIR}/examples_cxx/example_sparse_grids" -fast) add_test(DREAM "${CMAKE_CURRENT_BINARY_DIR}/examples_cxx/example_dream" -fast) add_test(Optimization "${CMAKE_CURRENT_BINARY_DIR}/examples_cxx/example_optimization" -fast) if (Tasmanian_FORTRAN_FOUND) add_test(Fortran "${CMAKE_CURRENT_BINARY_DIR}/examples_cxx/example_sparse_grids_fortran" -fast) endif() if (Tasmanian_PYTHON_FOUND) add_test(NAME Python::SparseGrids COMMAND @Python_EXECUTABLE@ "@Tasmanian_final_install_path@/share/Tasmanian/examples/example_sparse_grids.py" -fast) add_test(NAME Python::DREAM COMMAND @Python_EXECUTABLE@ "@Tasmanian_final_install_path@/share/Tasmanian/examples/example_dream.py" -fast) add_test(NAME Python::Optimization COMMAND @Python_EXECUTABLE@ "@Tasmanian_final_install_path@/share/Tasmanian/examples/example_optimization.py" -fast) endif() TASMANIAN-8.1/Testing/tasmanian_version.cpp000066400000000000000000000061431470551176200205520ustar00rootroot00000000000000/* * Copyright (c) 2017, Miroslav Stoyanov * * This file is part of * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND IMPLIED. * THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, * COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. * THE USER ASSUMES RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING FROM OR ARISING OUT OF, * IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE. */ #include "Tasmanian.hpp" /*! * \internal * \file tasmanian_version.cpp * \brief Test bare include. * \author Miroslav Stoyanov * \ingroup * * The sole purpose of this file is to test the master header Tasmanian.hpp * and the master cmake target Tasmanian::Tasmanian. */ #ifdef __TASMANIAN_BLAS_WRAPPERS_HPP #error "Internal file tsgBlasWrappers.hpp included globally" #endif int main(int, char**){ std::cout << "Tasmanian version: " << TASMANIAN_VERSION_STRING << "\n"; std::cout << " modules\n"; std::cout << " Sparse Grid: v" << TasGrid::TasmanianSparseGrid::getVersion() << "\n"; std::cout << " DREAM: v" << TasDREAM::TasmanianDREAM::getVersion() << "\n"; std::cout << "\nnote: all versions must match\n"; std::cout << std::endl; return 0; } TASMANIAN-8.1/Testing/test_post_install.in.sh000077500000000000000000000013661470551176200210460ustar00rootroot00000000000000#!/usr/bin/env bash if (( @Tasmanian_TESTS_OMP_NUM_THREADS@ != -1 )); then export OMP_NUM_THREADS=@Tasmanian_TESTS_OMP_NUM_THREADS@ fi source "@Tasmanian_final_install_path@"/share/Tasmanian/TasmanianENVsetup.sh || { echo "ERROR: Could not source /share/Tasmanian/TasmanianENVsetup.sh"; exit 1; } if [[ $(basename "$(pwd)") != "tasmanian_test_install" ]]; then if [ -d tasmanian_test_install ]; then cd tasmanian_test_install else echo "ERROR: must run this script from the tasmanian_test_install folder or the CMake build root folder" exit 1 fi fi rm -fr ../tasmanian_test_install/* @CMAKE_COMMAND@ @Tasmanian_compilers@ "@Tasmanian_final_install_path@/share/Tasmanian/testing" make -j make test